@behindthemusictree/app-kit-ui 37.1.0 → 38.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-DKQQLLMY.js → chunk-2GH7CSCE.js} +3 -3
- package/dist/{chunk-DKQQLLMY.js.map → chunk-2GH7CSCE.js.map} +1 -1
- package/dist/{chunk-57OI426Y.js → chunk-F7H5XPWU.js} +36 -36
- package/dist/chunk-F7H5XPWU.js.map +1 -0
- package/dist/{chunk-K4WMHUNM.js → chunk-NJYEQ3RS.js} +8 -8
- package/dist/chunk-NJYEQ3RS.js.map +1 -0
- package/dist/genre-tree/index.cjs +36 -36
- package/dist/genre-tree/index.cjs.map +1 -1
- package/dist/genre-tree/index.js +2 -2
- package/dist/index.cjs +42 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +3 -3
- package/dist/popup/index.cjs +8 -8
- package/dist/popup/index.cjs.map +1 -1
- package/dist/popup/index.js +2 -2
- package/package.json +5 -5
- package/dist/chunk-57OI426Y.js.map +0 -1
- package/dist/chunk-K4WMHUNM.js.map +0 -1
|
@@ -200,7 +200,7 @@ function Toast({ message, onClose, durationMs = 2200 }) {
|
|
|
200
200
|
role: "status",
|
|
201
201
|
"aria-live": "polite",
|
|
202
202
|
"aria-atomic": "true",
|
|
203
|
-
className: "pointer-events-auto w-full max-w-md rounded-md bg-[var(--color-surface)] px-4 py-4 text-
|
|
203
|
+
className: "pointer-events-auto w-full max-w-md rounded-md bg-[var(--color-surface)] px-4 py-4 text-body text-[var(--color-text)] shadow-lg ring-1 ring-black/10",
|
|
204
204
|
children: message
|
|
205
205
|
}
|
|
206
206
|
) }),
|
|
@@ -226,7 +226,7 @@ function InternalErrorPopup({ errorCode, contactEmail, ...rest }) {
|
|
|
226
226
|
" ",
|
|
227
227
|
/* @__PURE__ */ jsx5("a", { href: `mailto:${contactEmail}`, className: "text-[var(--color-primary)] hover:text-[var(--color-primary-hover)]", children: contactEmail })
|
|
228
228
|
] }) }),
|
|
229
|
-
errorCode && /* @__PURE__ */ jsxs3("div", { className: "text-
|
|
229
|
+
errorCode && /* @__PURE__ */ jsxs3("div", { className: "text-body text-[var(--color-neutral-500)] bg-[var(--color-neutral-100)] p-3 rounded-lg border border-[var(--color-neutral-100)]", children: [
|
|
230
230
|
"Error Code: ",
|
|
231
231
|
errorCode
|
|
232
232
|
] })
|
|
@@ -243,4 +243,4 @@ export {
|
|
|
243
243
|
Toast,
|
|
244
244
|
InternalErrorPopup
|
|
245
245
|
};
|
|
246
|
-
//# sourceMappingURL=chunk-
|
|
246
|
+
//# sourceMappingURL=chunk-2GH7CSCE.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/popup/PopupTitle.tsx","../src/popup/PopupButtons.tsx","../src/popup/BasePopup.tsx","../src/popup/Toast.tsx","../src/popup/InternalErrorPopup.tsx"],"sourcesContent":["\"use client\";\n\nimport { X } from \"lucide-react\";\nimport { Button } from \"@behindthemusictree/ui\";\nimport { LucideIcon } from \"lucide-react\";\n\ninterface PopupTitleProps {\n title: string;\n onClose: () => void;\n isDismissable?: boolean;\n icon?: LucideIcon;\n className?: string;\n titleClassName?: string;\n closeButtonClassName?: string;\n}\n\nexport function PopupTitle({\n title,\n onClose,\n isDismissable,\n icon: Icon,\n className = \"\",\n titleClassName = \"\",\n closeButtonClassName = \"\",\n}: PopupTitleProps) {\n return (\n <div className={`popup-title flex items-center justify-between bg-black p-4 rounded-t-lg ${className}`}>\n <div className=\"flex items-center gap-2\">\n {Icon && <Icon className=\"h-5 w-5 text-white\" />}\n <h3 id=\"popup-title\" className={`text-white font-semibold ${titleClassName}`}>\n {title}\n </h3>\n </div>\n {isDismissable && (\n <Button\n onClick={onClose}\n className={`h-8 w-8 text-white hover:text-white/80 ${closeButtonClassName}`}\n aria-label=\"Close popup\"\n >\n <X className=\"h-4 w-4\" />\n </Button>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport { ReactNode } from \"react\";\n\ninterface PopupButtonsProps {\n children: ReactNode;\n alignment?: \"left\" | \"center\" | \"right\";\n className?: string;\n}\n\nexport function PopupButtons({ children, alignment = \"center\", className = \"\" }: PopupButtonsProps) {\n const alignmentClasses = {\n left: \"justify-start\",\n center: \"justify-center\",\n right: \"justify-end\",\n };\n\n return <div className={`flex gap-3 ${alignmentClasses[alignment]} ${className}`}>{children}</div>;\n}\n","\"use client\";\n\nimport { createPortal } from \"react-dom\";\nimport { ReactNode, useEffect, useRef } from \"react\";\nimport { PopupTitle } from \"./PopupTitle\";\nimport { PopupButtons } from \"./PopupButtons\";\nimport { Button } from \"@behindthemusictree/ui\";\nimport { LucideIcon } from \"lucide-react\";\n\nexport interface BasePopupProps {\n title: string;\n children: ReactNode;\n onClose?: () => void;\n type?: \"default\" | \"success\" | \"error\" | \"warning\" | \"info\" | \"spotify\" | \"auth\";\n icon?: LucideIcon;\n isDismissable?: boolean;\n className?: string;\n overlayClassName?: string;\n titleClassName?: string;\n titleTextClassName?: string;\n closeButtonClassName?: string;\n /** Sizes the popup to its content (up to the type's max width) instead of filling it. */\n fitContent?: boolean;\n contentClassName?: string;\n showOkButton?: boolean;\n showCancelButton?: boolean;\n okButtonText?: string;\n okButtonDisabled?: boolean;\n cancelButtonText?: string;\n onOk?: () => void;\n onCancel?: () => void;\n buttonAlignment?: \"left\" | \"center\" | \"right\";\n /**\n * Distance (in px) reserved at the top of the viewport, e.g. for a fixed app header/banner.\n * Each consuming app passes its own value. Defaults to 0.\n */\n topOffset?: number;\n /** Keeps keyboard focus within the popup and restores it to the opener when dismissed. */\n trapFocus?: boolean;\n /** Closes a dismissable popup on Escape. */\n closeOnEscape?: boolean;\n /** Closes a dismissable popup when the backdrop is clicked. */\n closeOnBackdrop?: boolean;\n}\n\nconst typeClasses: Record<string, string> = {\n default: \"w-full max-w-lg\",\n success: \"w-full max-w-lg\",\n error: \"w-full max-w-lg\",\n warning: \"w-full max-w-lg\",\n info: \"w-full max-w-lg\",\n spotify: \"w-full max-w-md\",\n auth: \"w-full max-w-md\",\n};\n\nconst contentBgClasses: Record<string, string> = {\n spotify: \"bg-green-500\",\n auth: \"bg-gray-800\",\n};\n\nexport function BasePopup(props: BasePopupProps) {\n const {\n title,\n children,\n onClose,\n type = \"default\",\n icon,\n isDismissable = true,\n className,\n overlayClassName = \"\",\n titleClassName = \"\",\n titleTextClassName = \"\",\n closeButtonClassName = \"\",\n fitContent = false,\n contentClassName = \"\",\n showOkButton = false,\n showCancelButton = false,\n okButtonText = \"OK\",\n cancelButtonText = \"Cancel\",\n onOk,\n okButtonDisabled = false,\n onCancel,\n buttonAlignment = \"center\",\n topOffset = 0,\n trapFocus = false,\n closeOnEscape = false,\n closeOnBackdrop = false,\n } = props;\n const dialogRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const previousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n const dialog = dialogRef.current;\n const focusableSelector =\n 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n const getFocusable = () =>\n Array.from(dialog?.querySelectorAll<HTMLElement>(focusableSelector) ?? []).filter(\n (element) => !element.hasAttribute(\"hidden\") && element.getAttribute(\"aria-hidden\") !== \"true\",\n );\n\n if (trapFocus) (getFocusable()[0] ?? dialog)?.focus();\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\" && closeOnEscape && isDismissable) {\n event.preventDefault();\n onClose?.();\n return;\n }\n if (!trapFocus || event.key !== \"Tab\") return;\n\n const focusable = getFocusable();\n if (focusable.length === 0) {\n event.preventDefault();\n dialog?.focus();\n return;\n }\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n if (event.shiftKey && (document.activeElement === first || !dialog?.contains(document.activeElement))) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && (document.activeElement === last || !dialog?.contains(document.activeElement))) {\n event.preventDefault();\n first.focus();\n }\n };\n\n if (trapFocus || closeOnEscape) document.addEventListener(\"keydown\", handleKeyDown);\n return () => {\n if (trapFocus || closeOnEscape) document.removeEventListener(\"keydown\", handleKeyDown);\n if (trapFocus && previousFocus?.isConnected) previousFocus.focus();\n };\n }, [closeOnEscape, isDismissable, onClose, trapFocus]);\n\n const baseClasses = \"bg-white rounded-lg\";\n\n const renderButtons = () => {\n if (!showOkButton && !showCancelButton) return null;\n\n return (\n <div className=\"mt-4 pt-4 border-t\">\n <PopupButtons alignment={buttonAlignment}>\n {showCancelButton && (\n <Button onClick={onCancel || onClose || (() => {})} variant=\"secondary\">\n {cancelButtonText}\n </Button>\n )}\n {showOkButton && (\n <Button onClick={onOk || onClose || (() => {})} disabled={okButtonDisabled}>\n {okButtonText}\n </Button>\n )}\n </PopupButtons>\n </div>\n );\n };\n\n const popupComponent = (\n <div\n className={`fixed z-50 flex items-center justify-center bg-transparent ${overlayClassName}`}\n style={{\n top: topOffset,\n left: 0,\n right: 0,\n bottom: 0,\n }}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"popup-title\"\n onClick={closeOnBackdrop && isDismissable ? onClose : undefined}\n >\n <div\n ref={dialogRef}\n tabIndex={trapFocus ? -1 : undefined}\n className={`${baseClasses} ${fitContent ? typeClasses[type].replace(\"w-full\", \"w-fit\") : typeClasses[type]} ${className || \"\"}`}\n onClick={(e) => e.stopPropagation()}\n >\n <PopupTitle\n title={title}\n onClose={onClose ?? (() => {})}\n isDismissable={isDismissable}\n icon={icon}\n className={titleClassName}\n titleClassName={titleTextClassName}\n closeButtonClassName={closeButtonClassName}\n />\n <div className={`popup-content rounded-b-lg p-4 ${contentBgClasses[type] ?? \"\"} ${contentClassName}`}>\n {children}\n {renderButtons()}\n </div>\n </div>\n </div>\n );\n\n return createPortal(popupComponent, document.body);\n}\n\nexport default BasePopup;\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\n\nexport type ToastProps = {\n message: string;\n onClose: () => void;\n durationMs?: number;\n};\n\nexport default function Toast({ message, onClose, durationMs = 2200 }: ToastProps) {\n const [mounted, setMounted] = useState(false);\n\n useEffect(() => {\n setMounted(true);\n const timeout = window.setTimeout(onClose, durationMs);\n return () => window.clearTimeout(timeout);\n }, [durationMs, onClose]);\n\n if (!mounted) return null;\n\n return createPortal(\n <div className=\"pointer-events-none fixed inset-x-0 bottom-8 z-[60] flex justify-center px-4\">\n <div\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n className=\"pointer-events-auto w-full max-w-md rounded-md bg-[var(--color-surface)] px-4 py-4 text-sm text-[var(--color-text)] shadow-lg ring-1 ring-black/10\"\n >\n {message}\n </div>\n </div>,\n document.body,\n );\n}\n","\"use client\";\n\nimport { AlertTriangle, AlertCircle } from \"lucide-react\";\nimport { BasePopup, BasePopupProps } from \"./BasePopup\";\nimport { ErrorCode } from \"@behindthemusictree/app-kit/transport\";\n\ntype InternalErrorPopupProps = Omit<BasePopupProps, \"title\" | \"children\" | \"icon\" | \"isDismissable\"> & {\n errorCode: ErrorCode;\n /**\n * Support contact email shown in the \"if the problem persists\" message. Passed by the\n * consuming app (from whatever env var / config it uses) so this package doesn't assume a\n * specific env var name.\n */\n contactEmail?: string | null;\n};\n\nexport default function InternalErrorPopup({ errorCode, contactEmail, ...rest }: InternalErrorPopupProps) {\n return (\n <BasePopup\n {...rest}\n title=\"Internal Error\"\n isDismissable={false}\n icon={AlertTriangle}\n children={\n <div className=\"flex flex-col items-center space-y-6 py-4\">\n <AlertCircle className=\"h-16 w-16 text-[var(--color-red-500)]\" strokeWidth={1.5} />\n <div>\n <p className=\"text-center text-[var(--color-neutral-600)]\">\n Please try again. If the problem persists, contact us at{\" \"}\n <a href={`mailto:${contactEmail}`} className=\"text-[var(--color-primary)] hover:text-[var(--color-primary-hover)]\">\n {contactEmail}\n </a>\n </p>\n </div>\n {errorCode && (\n <div className=\"text-sm text-[var(--color-neutral-500)] bg-[var(--color-neutral-100)] p-3 rounded-lg border border-[var(--color-neutral-100)]\">\n Error Code: {errorCode}\n </div>\n )}\n </div>\n }\n />\n );\n}\n"],"mappings":"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","names":["jsx","Button","jsx","jsxs","useEffect","createPortal","jsx","jsx","jsxs"]}
|
|
1
|
+
{"version":3,"sources":["../src/popup/PopupTitle.tsx","../src/popup/PopupButtons.tsx","../src/popup/BasePopup.tsx","../src/popup/Toast.tsx","../src/popup/InternalErrorPopup.tsx"],"sourcesContent":["\"use client\";\n\nimport { X } from \"lucide-react\";\nimport { Button } from \"@behindthemusictree/ui\";\nimport { LucideIcon } from \"lucide-react\";\n\ninterface PopupTitleProps {\n title: string;\n onClose: () => void;\n isDismissable?: boolean;\n icon?: LucideIcon;\n className?: string;\n titleClassName?: string;\n closeButtonClassName?: string;\n}\n\nexport function PopupTitle({\n title,\n onClose,\n isDismissable,\n icon: Icon,\n className = \"\",\n titleClassName = \"\",\n closeButtonClassName = \"\",\n}: PopupTitleProps) {\n return (\n <div className={`popup-title flex items-center justify-between bg-black p-4 rounded-t-lg ${className}`}>\n <div className=\"flex items-center gap-2\">\n {Icon && <Icon className=\"h-5 w-5 text-white\" />}\n <h3 id=\"popup-title\" className={`text-white font-semibold ${titleClassName}`}>\n {title}\n </h3>\n </div>\n {isDismissable && (\n <Button\n onClick={onClose}\n className={`h-8 w-8 text-white hover:text-white/80 ${closeButtonClassName}`}\n aria-label=\"Close popup\"\n >\n <X className=\"h-4 w-4\" />\n </Button>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport { ReactNode } from \"react\";\n\ninterface PopupButtonsProps {\n children: ReactNode;\n alignment?: \"left\" | \"center\" | \"right\";\n className?: string;\n}\n\nexport function PopupButtons({ children, alignment = \"center\", className = \"\" }: PopupButtonsProps) {\n const alignmentClasses = {\n left: \"justify-start\",\n center: \"justify-center\",\n right: \"justify-end\",\n };\n\n return <div className={`flex gap-3 ${alignmentClasses[alignment]} ${className}`}>{children}</div>;\n}\n","\"use client\";\n\nimport { createPortal } from \"react-dom\";\nimport { ReactNode, useEffect, useRef } from \"react\";\nimport { PopupTitle } from \"./PopupTitle\";\nimport { PopupButtons } from \"./PopupButtons\";\nimport { Button } from \"@behindthemusictree/ui\";\nimport { LucideIcon } from \"lucide-react\";\n\nexport interface BasePopupProps {\n title: string;\n children: ReactNode;\n onClose?: () => void;\n type?: \"default\" | \"success\" | \"error\" | \"warning\" | \"info\" | \"spotify\" | \"auth\";\n icon?: LucideIcon;\n isDismissable?: boolean;\n className?: string;\n overlayClassName?: string;\n titleClassName?: string;\n titleTextClassName?: string;\n closeButtonClassName?: string;\n /** Sizes the popup to its content (up to the type's max width) instead of filling it. */\n fitContent?: boolean;\n contentClassName?: string;\n showOkButton?: boolean;\n showCancelButton?: boolean;\n okButtonText?: string;\n okButtonDisabled?: boolean;\n cancelButtonText?: string;\n onOk?: () => void;\n onCancel?: () => void;\n buttonAlignment?: \"left\" | \"center\" | \"right\";\n /**\n * Distance (in px) reserved at the top of the viewport, e.g. for a fixed app header/banner.\n * Each consuming app passes its own value. Defaults to 0.\n */\n topOffset?: number;\n /** Keeps keyboard focus within the popup and restores it to the opener when dismissed. */\n trapFocus?: boolean;\n /** Closes a dismissable popup on Escape. */\n closeOnEscape?: boolean;\n /** Closes a dismissable popup when the backdrop is clicked. */\n closeOnBackdrop?: boolean;\n}\n\nconst typeClasses: Record<string, string> = {\n default: \"w-full max-w-lg\",\n success: \"w-full max-w-lg\",\n error: \"w-full max-w-lg\",\n warning: \"w-full max-w-lg\",\n info: \"w-full max-w-lg\",\n spotify: \"w-full max-w-md\",\n auth: \"w-full max-w-md\",\n};\n\nconst contentBgClasses: Record<string, string> = {\n spotify: \"bg-green-500\",\n auth: \"bg-gray-800\",\n};\n\nexport function BasePopup(props: BasePopupProps) {\n const {\n title,\n children,\n onClose,\n type = \"default\",\n icon,\n isDismissable = true,\n className,\n overlayClassName = \"\",\n titleClassName = \"\",\n titleTextClassName = \"\",\n closeButtonClassName = \"\",\n fitContent = false,\n contentClassName = \"\",\n showOkButton = false,\n showCancelButton = false,\n okButtonText = \"OK\",\n cancelButtonText = \"Cancel\",\n onOk,\n okButtonDisabled = false,\n onCancel,\n buttonAlignment = \"center\",\n topOffset = 0,\n trapFocus = false,\n closeOnEscape = false,\n closeOnBackdrop = false,\n } = props;\n const dialogRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const previousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n const dialog = dialogRef.current;\n const focusableSelector =\n 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n const getFocusable = () =>\n Array.from(dialog?.querySelectorAll<HTMLElement>(focusableSelector) ?? []).filter(\n (element) => !element.hasAttribute(\"hidden\") && element.getAttribute(\"aria-hidden\") !== \"true\",\n );\n\n if (trapFocus) (getFocusable()[0] ?? dialog)?.focus();\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\" && closeOnEscape && isDismissable) {\n event.preventDefault();\n onClose?.();\n return;\n }\n if (!trapFocus || event.key !== \"Tab\") return;\n\n const focusable = getFocusable();\n if (focusable.length === 0) {\n event.preventDefault();\n dialog?.focus();\n return;\n }\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n if (event.shiftKey && (document.activeElement === first || !dialog?.contains(document.activeElement))) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && (document.activeElement === last || !dialog?.contains(document.activeElement))) {\n event.preventDefault();\n first.focus();\n }\n };\n\n if (trapFocus || closeOnEscape) document.addEventListener(\"keydown\", handleKeyDown);\n return () => {\n if (trapFocus || closeOnEscape) document.removeEventListener(\"keydown\", handleKeyDown);\n if (trapFocus && previousFocus?.isConnected) previousFocus.focus();\n };\n }, [closeOnEscape, isDismissable, onClose, trapFocus]);\n\n const baseClasses = \"bg-white rounded-lg\";\n\n const renderButtons = () => {\n if (!showOkButton && !showCancelButton) return null;\n\n return (\n <div className=\"mt-4 pt-4 border-t\">\n <PopupButtons alignment={buttonAlignment}>\n {showCancelButton && (\n <Button onClick={onCancel || onClose || (() => {})} variant=\"secondary\">\n {cancelButtonText}\n </Button>\n )}\n {showOkButton && (\n <Button onClick={onOk || onClose || (() => {})} disabled={okButtonDisabled}>\n {okButtonText}\n </Button>\n )}\n </PopupButtons>\n </div>\n );\n };\n\n const popupComponent = (\n <div\n className={`fixed z-50 flex items-center justify-center bg-transparent ${overlayClassName}`}\n style={{\n top: topOffset,\n left: 0,\n right: 0,\n bottom: 0,\n }}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"popup-title\"\n onClick={closeOnBackdrop && isDismissable ? onClose : undefined}\n >\n <div\n ref={dialogRef}\n tabIndex={trapFocus ? -1 : undefined}\n className={`${baseClasses} ${fitContent ? typeClasses[type].replace(\"w-full\", \"w-fit\") : typeClasses[type]} ${className || \"\"}`}\n onClick={(e) => e.stopPropagation()}\n >\n <PopupTitle\n title={title}\n onClose={onClose ?? (() => {})}\n isDismissable={isDismissable}\n icon={icon}\n className={titleClassName}\n titleClassName={titleTextClassName}\n closeButtonClassName={closeButtonClassName}\n />\n <div className={`popup-content rounded-b-lg p-4 ${contentBgClasses[type] ?? \"\"} ${contentClassName}`}>\n {children}\n {renderButtons()}\n </div>\n </div>\n </div>\n );\n\n return createPortal(popupComponent, document.body);\n}\n\nexport default BasePopup;\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\n\nexport type ToastProps = {\n message: string;\n onClose: () => void;\n durationMs?: number;\n};\n\nexport default function Toast({ message, onClose, durationMs = 2200 }: ToastProps) {\n const [mounted, setMounted] = useState(false);\n\n useEffect(() => {\n setMounted(true);\n const timeout = window.setTimeout(onClose, durationMs);\n return () => window.clearTimeout(timeout);\n }, [durationMs, onClose]);\n\n if (!mounted) return null;\n\n return createPortal(\n <div className=\"pointer-events-none fixed inset-x-0 bottom-8 z-[60] flex justify-center px-4\">\n <div\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n className=\"pointer-events-auto w-full max-w-md rounded-md bg-[var(--color-surface)] px-4 py-4 text-body text-[var(--color-text)] shadow-lg ring-1 ring-black/10\"\n >\n {message}\n </div>\n </div>,\n document.body,\n );\n}\n","\"use client\";\n\nimport { AlertTriangle, AlertCircle } from \"lucide-react\";\nimport { BasePopup, BasePopupProps } from \"./BasePopup\";\nimport { ErrorCode } from \"@behindthemusictree/app-kit/transport\";\n\ntype InternalErrorPopupProps = Omit<BasePopupProps, \"title\" | \"children\" | \"icon\" | \"isDismissable\"> & {\n errorCode: ErrorCode;\n /**\n * Support contact email shown in the \"if the problem persists\" message. Passed by the\n * consuming app (from whatever env var / config it uses) so this package doesn't assume a\n * specific env var name.\n */\n contactEmail?: string | null;\n};\n\nexport default function InternalErrorPopup({ errorCode, contactEmail, ...rest }: InternalErrorPopupProps) {\n return (\n <BasePopup\n {...rest}\n title=\"Internal Error\"\n isDismissable={false}\n icon={AlertTriangle}\n children={\n <div className=\"flex flex-col items-center space-y-6 py-4\">\n <AlertCircle className=\"h-16 w-16 text-[var(--color-red-500)]\" strokeWidth={1.5} />\n <div>\n <p className=\"text-center text-[var(--color-neutral-600)]\">\n Please try again. If the problem persists, contact us at{\" \"}\n <a href={`mailto:${contactEmail}`} className=\"text-[var(--color-primary)] hover:text-[var(--color-primary-hover)]\">\n {contactEmail}\n </a>\n </p>\n </div>\n {errorCode && (\n <div className=\"text-body text-[var(--color-neutral-500)] bg-[var(--color-neutral-100)] p-3 rounded-lg border border-[var(--color-neutral-100)]\">\n Error Code: {errorCode}\n </div>\n )}\n </div>\n }\n />\n );\n}\n"],"mappings":"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","names":["jsx","Button","jsx","jsxs","useEffect","createPortal","jsx","jsx","jsxs"]}
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
BasePopup_default,
|
|
3
3
|
InternalErrorPopup,
|
|
4
4
|
Toast
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-2GH7CSCE.js";
|
|
6
6
|
|
|
7
7
|
// src/genre-tree/GenreTreeView.tsx
|
|
8
8
|
import { useCallback as useCallback6, useDeferredValue as useDeferredValue2, useEffect as useEffect5, useMemo as useMemo8, useRef as useRef3, useState as useState9 } from "react";
|
|
@@ -545,7 +545,7 @@ function useArtistSearchGroup(getBaseUrl, text, onSelect, enabled = true) {
|
|
|
545
545
|
artist.disambiguation
|
|
546
546
|
] })
|
|
547
547
|
] }),
|
|
548
|
-
artist.matchedAlias && /* @__PURE__ */ jsxs2("span", { className: "block truncate text-
|
|
548
|
+
artist.matchedAlias && /* @__PURE__ */ jsxs2("span", { className: "block truncate text-caption text-[var(--color-neutral-500)]", children: [
|
|
549
549
|
"also known as ",
|
|
550
550
|
artist.matchedAlias
|
|
551
551
|
] })
|
|
@@ -573,7 +573,7 @@ function useSongSearchGroup(getBaseUrl, text, onSelect, enabled = true) {
|
|
|
573
573
|
key: song.uuid,
|
|
574
574
|
content: /* @__PURE__ */ jsxs3("span", { className: isSongSearchResultPlayable(song) ? void 0 : "opacity-60", children: [
|
|
575
575
|
/* @__PURE__ */ jsx6("span", { className: "block truncate font-medium", children: song.title }),
|
|
576
|
-
/* @__PURE__ */ jsx6("span", { className: "block truncate text-
|
|
576
|
+
/* @__PURE__ */ jsx6("span", { className: "block truncate text-caption text-[var(--color-neutral-500)]", children: [song.artists.map((artist) => artist.name).join(", "), song.genre?.name ?? "No genre"].filter(Boolean).join(" \xB7 ") })
|
|
577
577
|
] }),
|
|
578
578
|
onSelect: () => onSelect(song)
|
|
579
579
|
})),
|
|
@@ -598,9 +598,9 @@ function useGenreRemoteSearchGroup(getBaseUrl, text, onSelect, { key = "genres",
|
|
|
598
598
|
content: /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
599
599
|
/* @__PURE__ */ jsxs4("span", { className: "block truncate font-medium", children: [
|
|
600
600
|
genre.name,
|
|
601
|
-
genre.isUmbrella && /* @__PURE__ */ jsx7("span", { className: "ml-2 text-
|
|
601
|
+
genre.isUmbrella && /* @__PURE__ */ jsx7("span", { className: "ml-2 text-caption font-normal italic text-[var(--color-text-muted)]", children: "umbrella" })
|
|
602
602
|
] }),
|
|
603
|
-
/* @__PURE__ */ jsx7("span", { className: "block truncate text-
|
|
603
|
+
/* @__PURE__ */ jsx7("span", { className: "block truncate text-caption text-[var(--color-neutral-500)]", children: describe?.(genre) ?? `${genre.treeName} \xB7 ${genre.root.name}` })
|
|
604
604
|
] }),
|
|
605
605
|
onSelect: () => onSelect(genre)
|
|
606
606
|
})),
|
|
@@ -641,7 +641,7 @@ function GenreSearch({
|
|
|
641
641
|
key: genrePlaylist.uuid,
|
|
642
642
|
content: /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
643
643
|
genrePlaylist.name,
|
|
644
|
-
genrePlaylist.isUmbrella && /* @__PURE__ */ jsx8("span", { className: "ml-2 text-
|
|
644
|
+
genrePlaylist.isUmbrella && /* @__PURE__ */ jsx8("span", { className: "ml-2 text-caption italic text-[var(--color-text-muted)]", children: "umbrella" })
|
|
645
645
|
] }),
|
|
646
646
|
onSelect: () => select(genrePlaylist)
|
|
647
647
|
}))
|
|
@@ -760,7 +760,7 @@ import { SiGmail } from "react-icons/si";
|
|
|
760
760
|
|
|
761
761
|
// src/genre-tree/ShareDestinationButton.tsx
|
|
762
762
|
import { Fragment as Fragment4, jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
763
|
-
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-
|
|
763
|
+
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-caption 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";
|
|
764
764
|
function Contents({ icon, label }) {
|
|
765
765
|
return /* @__PURE__ */ jsxs6(Fragment4, { children: [
|
|
766
766
|
/* @__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 }),
|
|
@@ -790,9 +790,9 @@ function SharePreviewCard({ target, url }) {
|
|
|
790
790
|
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: [
|
|
791
791
|
/* @__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" }) }),
|
|
792
792
|
/* @__PURE__ */ jsxs7("div", { className: "flex min-w-0 flex-1 flex-col justify-center gap-1 p-4", children: [
|
|
793
|
-
/* @__PURE__ */ jsx11("span", { className: "text-
|
|
793
|
+
/* @__PURE__ */ jsx11("span", { className: "text-caption font-medium uppercase tracking-wide text-[var(--color-text-muted)]", children: typeLabel }),
|
|
794
794
|
/* @__PURE__ */ jsx11("span", { className: "truncate text-base font-semibold text-[var(--color-text)]", title: target.name, children: target.name }),
|
|
795
|
-
/* @__PURE__ */ jsx11("span", { className: "truncate text-
|
|
795
|
+
/* @__PURE__ */ jsx11("span", { className: "truncate text-body text-[var(--color-primary)]", title: url, children: url })
|
|
796
796
|
] })
|
|
797
797
|
] }) });
|
|
798
798
|
}
|
|
@@ -933,8 +933,8 @@ function SharePopup({ target, url, onClose }) {
|
|
|
933
933
|
}
|
|
934
934
|
)
|
|
935
935
|
] }),
|
|
936
|
-
copyStatus === "failed" && /* @__PURE__ */ jsx12("p", { role: "alert", className: "text-center text-
|
|
937
|
-
shareError && /* @__PURE__ */ jsx12("p", { role: "alert", className: "text-center text-
|
|
936
|
+
copyStatus === "failed" && /* @__PURE__ */ jsx12("p", { role: "alert", className: "text-center text-body text-[var(--color-red-500)]", children: "Could not copy the link." }),
|
|
937
|
+
shareError && /* @__PURE__ */ jsx12("p", { role: "alert", className: "text-center text-body text-[var(--color-red-500)]", children: shareError })
|
|
938
938
|
] })
|
|
939
939
|
}
|
|
940
940
|
),
|
|
@@ -954,7 +954,7 @@ function ShareActionButton({ target, url }) {
|
|
|
954
954
|
{
|
|
955
955
|
type: "button",
|
|
956
956
|
onClick: openSharePopup,
|
|
957
|
-
className: "group flex flex-col items-center gap-1 w-16 text-
|
|
957
|
+
className: "group flex flex-col items-center gap-1 w-16 text-caption text-center text-[var(--color-text)] focus-visible:outline-none",
|
|
958
958
|
"aria-label": `Share ${target.name}`,
|
|
959
959
|
title: `Share ${target.name}`,
|
|
960
960
|
children: [
|
|
@@ -1036,7 +1036,7 @@ function GenreActionBand({
|
|
|
1036
1036
|
disabled: item.disabled,
|
|
1037
1037
|
title: item.title,
|
|
1038
1038
|
onClick: item.onClick,
|
|
1039
|
-
className: "group flex flex-col items-center gap-1 w-16 text-
|
|
1039
|
+
className: "group flex flex-col items-center gap-1 w-16 text-caption text-center text-[var(--color-text)] focus-visible:outline-none disabled:opacity-50",
|
|
1040
1040
|
children: [
|
|
1041
1041
|
/* @__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 }),
|
|
1042
1042
|
item.label
|
|
@@ -1055,7 +1055,7 @@ function GenreActionBand({
|
|
|
1055
1055
|
"aria-label": "Admin actions",
|
|
1056
1056
|
className: `px-3.5 py-3 ${items.length > 0 ? "border-t border-[var(--color-border)]" : ""}`,
|
|
1057
1057
|
children: [
|
|
1058
|
-
/* @__PURE__ */ jsx14("h3", { className: "mb-2 text-
|
|
1058
|
+
/* @__PURE__ */ jsx14("h3", { className: "mb-2 text-caption font-semibold uppercase tracking-wide text-[var(--color-text-muted)]", children: "Admin" }),
|
|
1059
1059
|
/* @__PURE__ */ jsx14("div", { className: "flex flex-wrap gap-1", children: renderItems(adminItems) })
|
|
1060
1060
|
]
|
|
1061
1061
|
}
|
|
@@ -1087,7 +1087,7 @@ function ClampedText({ children, className: className2 = "" }) {
|
|
|
1087
1087
|
type: "button",
|
|
1088
1088
|
"aria-expanded": expanded,
|
|
1089
1089
|
onClick: () => setExpanded((value) => !value),
|
|
1090
|
-
className: "mt-1 text-
|
|
1090
|
+
className: "mt-1 text-caption text-[var(--color-text-muted)] underline hover:text-[var(--color-text)]",
|
|
1091
1091
|
children: expanded ? "Show less" : "Show more"
|
|
1092
1092
|
}
|
|
1093
1093
|
)
|
|
@@ -1238,7 +1238,7 @@ function GenrePlaylistTracks({
|
|
|
1238
1238
|
".",
|
|
1239
1239
|
" ",
|
|
1240
1240
|
/* @__PURE__ */ jsx17("button", { type: "button", className: "underline", onClick: () => void refetch(), children: "Retry" })
|
|
1241
|
-
] }) : tracks.length === 0 ? /* @__PURE__ */ jsx17("p", { children: "\u2014" }) : /* @__PURE__ */ jsxs12("ul", { className: "mt-1 max-h-64 overflow-y-auto text-
|
|
1241
|
+
] }) : tracks.length === 0 ? /* @__PURE__ */ jsx17("p", { children: "\u2014" }) : /* @__PURE__ */ jsxs12("ul", { className: "mt-1 max-h-64 overflow-y-auto text-body [container-type:inline-size]", "aria-label": `${genreName} ${trackNoun.plural}`, children: [
|
|
1242
1242
|
tracks.map((track, index) => {
|
|
1243
1243
|
const label = track.artists?.length ? `${track.title} \u2014 ${track.artists.map((artist2) => artist2.name).join(", ")}` : track.title;
|
|
1244
1244
|
const isCurrent = playerTrackObject?.track.id === track.uuid;
|
|
@@ -1336,7 +1336,7 @@ function GenreDetailExtras({
|
|
|
1336
1336
|
const { summary, summarySourceUrl, essentialSongs } = overview;
|
|
1337
1337
|
const wikidataUrl = wikidataId ? `https://www.wikidata.org/wiki/${encodeURIComponent(wikidataId)}` : null;
|
|
1338
1338
|
return /* @__PURE__ */ jsxs13(Fragment8, { children: [
|
|
1339
|
-
(summarySourceUrl || wikidataUrl) && /* @__PURE__ */ jsx18(PanelSection2, { title: "Links", children: /* @__PURE__ */ jsxs13("div", { className: "flex flex-wrap gap-x-3 gap-y-1 text-
|
|
1339
|
+
(summarySourceUrl || wikidataUrl) && /* @__PURE__ */ jsx18(PanelSection2, { title: "Links", children: /* @__PURE__ */ jsxs13("div", { className: "flex flex-wrap gap-x-3 gap-y-1 text-caption text-[var(--color-text)]", children: [
|
|
1340
1340
|
summarySourceUrl && /* @__PURE__ */ jsxs13(
|
|
1341
1341
|
"a",
|
|
1342
1342
|
{
|
|
@@ -1364,10 +1364,10 @@ function GenreDetailExtras({
|
|
|
1364
1364
|
}
|
|
1365
1365
|
)
|
|
1366
1366
|
] }) }),
|
|
1367
|
-
/* @__PURE__ */ jsx18(PanelSection2, { title: "Summary", children: renderSummary ? renderSummary(overview) : /* @__PURE__ */ jsx18(ClampedText, { className: "text-
|
|
1367
|
+
/* @__PURE__ */ jsx18(PanelSection2, { title: "Summary", children: renderSummary ? renderSummary(overview) : /* @__PURE__ */ jsx18(ClampedText, { className: "text-body text-[var(--color-text)]", children: summary ?? "\u2014" }, genreUuid) }),
|
|
1368
1368
|
family,
|
|
1369
1369
|
renderGenreDetailExtras?.(overview),
|
|
1370
|
-
(renderEssentialTracks || essentialSongs) && /* @__PURE__ */ jsx18(PanelSection2, { title: `Essential ${trackNoun.plural}`, children: renderEssentialTracks ? renderEssentialTracks(overview) : essentialSongs && essentialSongs.length > 0 ? /* @__PURE__ */ jsx18("ul", { className: "text-
|
|
1370
|
+
(renderEssentialTracks || essentialSongs) && /* @__PURE__ */ jsx18(PanelSection2, { title: `Essential ${trackNoun.plural}`, children: renderEssentialTracks ? renderEssentialTracks(overview) : essentialSongs && essentialSongs.length > 0 ? /* @__PURE__ */ jsx18("ul", { className: "text-body text-[var(--color-text)]", children: essentialSongs.map((track) => /* @__PURE__ */ jsx18("li", { className: "py-1", children: track.title }, track.uuid)) }) : /* @__PURE__ */ jsx18("p", { className: "text-body text-[var(--color-text)]", children: "\u2014" }) }),
|
|
1371
1371
|
/* @__PURE__ */ jsx18(
|
|
1372
1372
|
GenrePlaylistTracks,
|
|
1373
1373
|
{
|
|
@@ -1433,7 +1433,7 @@ function GenreInfoPanelBody({
|
|
|
1433
1433
|
return /* @__PURE__ */ jsxs14(Fragment9, { children: [
|
|
1434
1434
|
toolbar,
|
|
1435
1435
|
genrePlaylist ? /* @__PURE__ */ jsx19(GenreNodeActionBand, { ...band, genrePlaylist, playback }) : /* @__PURE__ */ jsx19(GenreActionBand, { ...band }),
|
|
1436
|
-
summary && catalogue && /* @__PURE__ */ jsxs14("div", { className: "px-3.5 py-3 text-
|
|
1436
|
+
summary && catalogue && /* @__PURE__ */ jsxs14("div", { className: "px-3.5 py-3 text-body text-[var(--color-text)]", children: [
|
|
1437
1437
|
/* @__PURE__ */ jsxs14("p", { children: [
|
|
1438
1438
|
"Catalogue ",
|
|
1439
1439
|
noun.plural,
|
|
@@ -1523,7 +1523,7 @@ function useGenreDetailContent({
|
|
|
1523
1523
|
if (isError) return {
|
|
1524
1524
|
name: null,
|
|
1525
1525
|
title: "Genre unavailable",
|
|
1526
|
-
content: /* @__PURE__ */ jsx20("p", { role: "alert", className: "p-4 text-
|
|
1526
|
+
content: /* @__PURE__ */ jsx20("p", { role: "alert", className: "p-4 text-body text-[var(--color-text)]", children: "This genre could not be loaded." })
|
|
1527
1527
|
};
|
|
1528
1528
|
if (isPending || !detail || !view) return {
|
|
1529
1529
|
name: null,
|
|
@@ -1662,7 +1662,7 @@ function ChangeParentPopup({
|
|
|
1662
1662
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
1663
1663
|
}, [onClose]);
|
|
1664
1664
|
return /* @__PURE__ */ jsxs16(BasePopup_default, { title: `Change parent of ${genrePlaylist.name}`, onClose, showCancelButton: true, fitContent: true, children: [
|
|
1665
|
-
/* @__PURE__ */ jsxs16("p", { className: "mb-3 text-
|
|
1665
|
+
/* @__PURE__ */ jsxs16("p", { className: "mb-3 text-body text-[var(--color-text-muted)]", children: [
|
|
1666
1666
|
"Current parent: ",
|
|
1667
1667
|
genrePlaylist.parent?.name ?? "none"
|
|
1668
1668
|
] }),
|
|
@@ -1674,7 +1674,7 @@ function ChangeParentPopup({
|
|
|
1674
1674
|
placeholder: "Search a new parent\u2026"
|
|
1675
1675
|
}
|
|
1676
1676
|
) }),
|
|
1677
|
-
formErrors.length > 0 && /* @__PURE__ */ jsx21("p", { role: "alert", className: "mt-3 text-
|
|
1677
|
+
formErrors.length > 0 && /* @__PURE__ */ jsx21("p", { role: "alert", className: "mt-3 text-body text-[var(--color-red-500)]", children: formErrors.map(({ message }) => message).join(" ") })
|
|
1678
1678
|
] });
|
|
1679
1679
|
}
|
|
1680
1680
|
|
|
@@ -1769,7 +1769,7 @@ function ExternalLink({ href, children }) {
|
|
|
1769
1769
|
function ArtistPhoto({ image, name }) {
|
|
1770
1770
|
return /* @__PURE__ */ jsxs17("figure", { className: "flex flex-col gap-1.5 px-6 py-2.5", children: [
|
|
1771
1771
|
/* @__PURE__ */ jsx24("img", { src: image.url, alt: name, className: "h-64 w-full object-contain bg-[var(--color-surface-muted)] rounded" }),
|
|
1772
|
-
/* @__PURE__ */ jsxs17("figcaption", { className: "text-
|
|
1772
|
+
/* @__PURE__ */ jsxs17("figcaption", { className: "text-caption text-[var(--color-text-muted)]", children: [
|
|
1773
1773
|
"Photo: ",
|
|
1774
1774
|
/* @__PURE__ */ jsx24(ExternalLink, { href: image.pageUrl, children: image.author ?? "Wikimedia Commons" }),
|
|
1775
1775
|
",",
|
|
@@ -1973,7 +1973,7 @@ function TrackItem({
|
|
|
1973
1973
|
/* @__PURE__ */ jsx28("div", { className: "flex max-w-full items-center gap-2", children: /* @__PURE__ */ jsx28("div", { className: "title text-lg font-bold text-[var(--color-text)] max-w-full truncate", children: renderSongLink ? renderSongLink(track) : isSong2(track) ? /* @__PURE__ */ jsx28(MusicBrainzRecordingLink, { song: track, className: "hover:underline focus-visible:underline", children: track.title }) : track.title }) }),
|
|
1974
1974
|
track.artists && track.artists.length > 0 ? /* @__PURE__ */ jsx28("div", { className: "artist text-base max-w-full truncate text-[var(--color-text-muted)]", children: /* @__PURE__ */ jsx28(ArtistNames2, { artists: track.artists, renderArtistLink }) }) : ""
|
|
1975
1975
|
] }),
|
|
1976
|
-
/* @__PURE__ */ jsx28("div", { className: "genre-name-container flex items-center justify-start w-[21.6%] min-w-0 shrink-0", children: track.genre ? /* @__PURE__ */ jsx28("div", { className: "genre-name max-w-full whitespace-normal break-words p-1 text-
|
|
1976
|
+
/* @__PURE__ */ jsx28("div", { className: "genre-name-container flex items-center justify-start w-[21.6%] min-w-0 shrink-0", children: track.genre ? /* @__PURE__ */ jsx28("div", { className: "genre-name max-w-full whitespace-normal break-words p-1 text-caption font-bold", children: track.genre.name }) : "" }),
|
|
1977
1977
|
renderDuration && /* @__PURE__ */ jsx28(
|
|
1978
1978
|
"div",
|
|
1979
1979
|
{
|
|
@@ -2029,14 +2029,14 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2029
2029
|
{
|
|
2030
2030
|
type: "button",
|
|
2031
2031
|
onClick: () => void play(),
|
|
2032
|
-
className: "flex w-fit items-center gap-1.5 px-3 py-1 text-
|
|
2032
|
+
className: "flex w-fit items-center gap-1.5 px-3 py-1 text-caption font-medium bg-gray-900 text-white rounded-full hover:bg-gray-700",
|
|
2033
2033
|
children: [
|
|
2034
2034
|
/* @__PURE__ */ jsx29(Play2, { className: "h-3.5 w-3.5", "aria-hidden": "true" }),
|
|
2035
2035
|
"Play all"
|
|
2036
2036
|
]
|
|
2037
2037
|
}
|
|
2038
2038
|
),
|
|
2039
|
-
/* @__PURE__ */ jsx29("div", { role: "group", "aria-label": "Sort songs by", className: "flex gap-1 text-
|
|
2039
|
+
/* @__PURE__ */ jsx29("div", { role: "group", "aria-label": "Sort songs by", className: "flex gap-1 text-caption", children: SORTS.map((sort) => /* @__PURE__ */ jsx29(
|
|
2040
2040
|
"button",
|
|
2041
2041
|
{
|
|
2042
2042
|
type: "button",
|
|
@@ -2165,7 +2165,7 @@ function SongHistory({ uuid, getBackendBaseUrl }) {
|
|
|
2165
2165
|
if (history.status === "loading") body = /* @__PURE__ */ jsx31(Skeleton6, { className: "h-10", "aria-busy": "true" });
|
|
2166
2166
|
else if (history.status === "error") body = /* @__PURE__ */ jsx31("p", { className: "text-red-600", children: "Could not load the history." });
|
|
2167
2167
|
else if (history.status === "success")
|
|
2168
|
-
body = history.entries.length === 0 ? /* @__PURE__ */ jsx31("p", { className: "text-[var(--color-text-muted)]", children: "No changes yet." }) : /* @__PURE__ */ jsx31("ul", { className: "divide-y divide-[var(--color-border)]", children: history.entries.map((entry) => /* @__PURE__ */ jsxs24("li", { className: "py-1.5 text-
|
|
2168
|
+
body = history.entries.length === 0 ? /* @__PURE__ */ jsx31("p", { className: "text-[var(--color-text-muted)]", children: "No changes yet." }) : /* @__PURE__ */ jsx31("ul", { className: "divide-y divide-[var(--color-border)]", children: history.entries.map((entry) => /* @__PURE__ */ jsxs24("li", { className: "py-1.5 text-body", children: [
|
|
2169
2169
|
/* @__PURE__ */ jsx31("span", { className: "font-medium", children: entry.action }),
|
|
2170
2170
|
entry.oldValue !== null || entry.newValue !== null ? /* @__PURE__ */ jsxs24("span", { className: "text-[var(--color-text-muted)]", children: [
|
|
2171
2171
|
" ",
|
|
@@ -2174,7 +2174,7 @@ function SongHistory({ uuid, getBackendBaseUrl }) {
|
|
|
2174
2174
|
" \u2192 ",
|
|
2175
2175
|
entry.newValue ?? "none"
|
|
2176
2176
|
] }) : null,
|
|
2177
|
-
/* @__PURE__ */ jsxs24("span", { className: "block text-
|
|
2177
|
+
/* @__PURE__ */ jsxs24("span", { className: "block text-caption text-[var(--color-text-muted)]", children: [
|
|
2178
2178
|
entry.actorPseudo ?? "Anonymous",
|
|
2179
2179
|
" \xB7 ",
|
|
2180
2180
|
dateFormat.format(new Date(entry.createdOn))
|
|
@@ -2247,12 +2247,12 @@ function SongPanelContent(props) {
|
|
|
2247
2247
|
});
|
|
2248
2248
|
return /* @__PURE__ */ jsxs24(Fragment13, { children: [
|
|
2249
2249
|
/* @__PURE__ */ jsx31("div", { className: "genre-action-band border-b border-[var(--color-border)]", children: /* @__PURE__ */ jsxs24("div", { className: "flex flex-wrap gap-1 px-3.5 py-3", children: [
|
|
2250
|
-
unplayableReason ? /* @__PURE__ */ jsx31("p", { className: "flex items-center px-2.5 text-
|
|
2250
|
+
unplayableReason ? /* @__PURE__ */ jsx31("p", { className: "flex items-center px-2.5 text-body text-[var(--color-text-muted)]", children: unplayableReason }) : /* @__PURE__ */ jsxs24(
|
|
2251
2251
|
"button",
|
|
2252
2252
|
{
|
|
2253
2253
|
type: "button",
|
|
2254
2254
|
onClick: () => isCurrent ? handlePlayPauseAction() : playNewTrackListFromTrackUuid(song, scope),
|
|
2255
|
-
className: "group flex flex-col items-center gap-1 w-16 text-
|
|
2255
|
+
className: "group flex flex-col items-center gap-1 w-16 text-caption text-center text-[var(--color-text)] focus-visible:outline-none",
|
|
2256
2256
|
children: [
|
|
2257
2257
|
/* @__PURE__ */ jsx31("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__ */ jsx31(Pause2, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ jsx31(Play3, { "aria-hidden": "true", className: "w-5 h-5" }) }),
|
|
2258
2258
|
isPlaying ? "Pause" : "Play"
|
|
@@ -2760,7 +2760,7 @@ function GenreTreeView({
|
|
|
2760
2760
|
) : null;
|
|
2761
2761
|
const renderArtistFilter = () => {
|
|
2762
2762
|
if (isLoading || !filterArtist) return null;
|
|
2763
|
-
return /* @__PURE__ */ jsxs26("span", { className: "inline-flex items-center overflow-hidden rounded-full bg-[var(--color-neutral-100)] text-
|
|
2763
|
+
return /* @__PURE__ */ jsxs26("span", { className: "inline-flex items-center overflow-hidden rounded-full bg-[var(--color-neutral-100)] text-body", children: [
|
|
2764
2764
|
/* @__PURE__ */ jsx34(
|
|
2765
2765
|
"button",
|
|
2766
2766
|
{
|
|
@@ -2871,14 +2871,14 @@ function GenreTreeView({
|
|
|
2871
2871
|
/* @__PURE__ */ jsx34(
|
|
2872
2872
|
"div",
|
|
2873
2873
|
{
|
|
2874
|
-
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"}`,
|
|
2874
|
+
className: `actions-container absolute z-30 flex items-center gap-2 ${placement === "regions" ? "left-[calc(var(--layout-gutter)+var(--layout-panel-inset))] top-[calc(var(--layout-gutter)+var(--layout-panel-inset))] md:left-[var(--layout-panel-inset)] md:top-[var(--layout-panel-inset)] max-md:right-[calc(var(--layout-gutter)+var(--layout-panel-inset))] max-md:top-[var(--layout-band-top)] max-md:flex-col max-md:items-stretch" : "left-5 top-5"}`,
|
|
2875
2875
|
children: actions
|
|
2876
2876
|
}
|
|
2877
2877
|
),
|
|
2878
2878
|
!isLoading && !isError && filterArtist && /* @__PURE__ */ jsx34(
|
|
2879
2879
|
"div",
|
|
2880
2880
|
{
|
|
2881
|
-
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"}`,
|
|
2881
|
+
className: `absolute left-1/2 z-30 hidden -translate-x-1/2 md:block ${placement === "regions" ? "top-[calc(var(--layout-gutter)+var(--layout-panel-inset))] md:top-[var(--layout-panel-inset)]" : "top-5"}`,
|
|
2882
2882
|
children: renderArtistFilter()
|
|
2883
2883
|
}
|
|
2884
2884
|
),
|
|
@@ -3153,7 +3153,7 @@ function TrackListSidebar({
|
|
|
3153
3153
|
/* @__PURE__ */ jsx35("div", { className: "from h-auto flex flex-col justify-center items-center mr-2", children: "From" }),
|
|
3154
3154
|
/* @__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 }) })
|
|
3155
3155
|
] }),
|
|
3156
|
-
/* @__PURE__ */ jsxs27("div", { className: "info flex items-center text-
|
|
3156
|
+
/* @__PURE__ */ jsxs27("div", { className: "info flex items-center text-body text-[var(--color-text-muted)]", children: [
|
|
3157
3157
|
trackList.origin.type === TrackListOriginType2.GENRE_PLAYLIST ? "Genre \u2022 " : trackList.origin.type === TrackListOriginType2.ARTIST ? "Artist \u2022 " : `${trackNoun.singular} playlist \u2022 `,
|
|
3158
3158
|
`${trackList.total} ${trackList.total > 1 ? trackNoun.plural : trackNoun.singular}`
|
|
3159
3159
|
] })
|
|
@@ -3558,4 +3558,4 @@ export {
|
|
|
3558
3558
|
GenreTreeViewSkeleton2 as GenreTreeViewSkeleton,
|
|
3559
3559
|
GenreTreeOutlineSkeleton
|
|
3560
3560
|
};
|
|
3561
|
-
//# sourceMappingURL=chunk-
|
|
3561
|
+
//# sourceMappingURL=chunk-F7H5XPWU.js.map
|