@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.
@@ -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-sm text-[var(--color-text)] shadow-lg ring-1 ring-black/10",
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-sm text-[var(--color-neutral-500)] bg-[var(--color-neutral-100)] p-3 rounded-lg border border-[var(--color-neutral-100)]", children: [
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-DKQQLLMY.js.map
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-DKQQLLMY.js";
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-xs text-[var(--color-neutral-500)]", children: [
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-xs text-[var(--color-neutral-500)]", children: [song.artists.map((artist) => artist.name).join(", "), song.genre?.name ?? "No genre"].filter(Boolean).join(" \xB7 ") })
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-xs font-normal italic text-[var(--color-text-muted)]", children: "umbrella" })
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-xs text-[var(--color-neutral-500)]", children: describe?.(genre) ?? `${genre.treeName} \xB7 ${genre.root.name}` })
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-xs italic text-[var(--color-text-muted)]", children: "umbrella" })
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-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";
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-xs font-medium uppercase tracking-wide text-[var(--color-text-muted)]", children: typeLabel }),
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-sm text-[var(--color-primary)]", title: url, children: url })
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-sm text-[var(--color-red-500)]", children: "Could not copy the link." }),
937
- shareError && /* @__PURE__ */ jsx12("p", { role: "alert", className: "text-center text-sm text-[var(--color-red-500)]", children: shareError })
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-xs text-center text-[var(--color-text)] focus-visible:outline-none",
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-xs text-center text-[var(--color-text)] focus-visible:outline-none disabled:opacity-50",
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-xs font-semibold uppercase tracking-wide text-[var(--color-text-muted)]", children: "Admin" }),
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-xs text-[var(--color-text-muted)] underline hover:text-[var(--color-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-[0.8125rem] leading-[1.45] [container-type:inline-size]", "aria-label": `${genreName} ${trackNoun.plural}`, children: [
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-xs text-[var(--color-text)]", children: [
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-[0.8125rem] leading-[1.45] text-[var(--color-text)]", children: summary ?? "\u2014" }, genreUuid) }),
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-[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" }) }),
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-sm text-[var(--color-text)]", children: [
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-sm text-[var(--color-text)]", children: "This genre could not be loaded." })
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-sm text-[var(--color-text-muted)]", children: [
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-sm text-[var(--color-red-500)]", children: formErrors.map(({ message }) => message).join(" ") })
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-xs text-[var(--color-text-muted)]", children: [
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-xs font-bold", children: track.genre.name }) : "" }),
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-xs font-medium bg-gray-900 text-white rounded-full hover:bg-gray-700",
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-xs", children: SORTS.map((sort) => /* @__PURE__ */ jsx29(
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-sm", children: [
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-xs text-[var(--color-text-muted)]", children: [
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-sm text-[var(--color-text-muted)]", children: unplayableReason }) : /* @__PURE__ */ jsxs24(
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-xs text-center text-[var(--color-text)] focus-visible:outline-none",
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-sm", children: [
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-sm text-[var(--color-text-muted)]", children: [
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-57OI426Y.js.map
3561
+ //# sourceMappingURL=chunk-F7H5XPWU.js.map