@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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BasePopup
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-2GH7CSCE.js";
|
|
4
4
|
|
|
5
5
|
// src/popup/TrackUploadPopup.tsx
|
|
6
6
|
import { MdError, MdCheckCircle, MdUpload } from "react-icons/md";
|
|
@@ -66,14 +66,14 @@ function TrackUploadPopup({
|
|
|
66
66
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-3", children: [
|
|
67
67
|
getStatusIcon(item.status),
|
|
68
68
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
69
|
-
/* @__PURE__ */ jsx("div", { className: "font-medium text-
|
|
70
|
-
/* @__PURE__ */ jsxs("div", { className: "text-
|
|
69
|
+
/* @__PURE__ */ jsx("div", { className: "font-medium text-body truncate max-w-xs", title: item.file.name, children: item.file.name }),
|
|
70
|
+
/* @__PURE__ */ jsxs("div", { className: "text-caption text-[var(--color-neutral-500)]", children: [
|
|
71
71
|
(item.file.size / 1024 / 1024).toFixed(1),
|
|
72
72
|
" MB"
|
|
73
73
|
] })
|
|
74
74
|
] })
|
|
75
75
|
] }),
|
|
76
|
-
/* @__PURE__ */ jsx("div", { className: "text-
|
|
76
|
+
/* @__PURE__ */ jsx("div", { className: "text-body text-[var(--color-neutral-600)]", children: getStatusText(item.status) })
|
|
77
77
|
] }),
|
|
78
78
|
item.status === "uploading" && /* @__PURE__ */ jsx("div", { className: "w-full bg-[var(--color-neutral-200)] rounded-full h-2", children: /* @__PURE__ */ jsx(
|
|
79
79
|
"div",
|
|
@@ -82,9 +82,9 @@ function TrackUploadPopup({
|
|
|
82
82
|
style: { width: `${item.progress}%` }
|
|
83
83
|
}
|
|
84
84
|
) }),
|
|
85
|
-
item.status === "error" && item.error && /* @__PURE__ */ jsx("div", { className: "text-[var(--color-red-500)] text-
|
|
85
|
+
item.status === "error" && item.error && /* @__PURE__ */ jsx("div", { className: "text-[var(--color-red-500)] text-body mt-2", children: item.error.name === "InvalidInputError" ? "Upload failed due to invalid file data. Please check your file and try again." : item.error.name === "ZodError" ? "Upload failed due to a server error. Please try again later." : item.error.message })
|
|
86
86
|
] }, item.id)),
|
|
87
|
-
allComplete && /* @__PURE__ */ jsx("div", { className: "flex justify-between items-center", children: /* @__PURE__ */ jsxs("div", { className: "text-
|
|
87
|
+
allComplete && /* @__PURE__ */ jsx("div", { className: "flex justify-between items-center", children: /* @__PURE__ */ jsxs("div", { className: "text-body text-[var(--color-neutral-600)]", children: [
|
|
88
88
|
successfulCount,
|
|
89
89
|
" successful, ",
|
|
90
90
|
errorCount,
|
|
@@ -222,7 +222,7 @@ function SpotifyAuthErrorPopup({
|
|
|
222
222
|
/* @__PURE__ */ jsx5(FaSpotify2, { className: "text-[#1DB954] text-7xl" }),
|
|
223
223
|
/* @__PURE__ */ jsxs5("div", { className: "space-y-3 text-center", children: [
|
|
224
224
|
/* @__PURE__ */ jsx5("p", { className: "text-xl font-medium text-[var(--color-text)]", children: message }),
|
|
225
|
-
details && /* @__PURE__ */ jsx5("p", { className: "text-
|
|
225
|
+
details && /* @__PURE__ */ jsx5("p", { className: "text-body text-[var(--color-neutral-500)] bg-[var(--color-neutral-100)] p-3 rounded-lg border border-[var(--color-neutral-100)]", children: details }),
|
|
226
226
|
/* @__PURE__ */ jsxs5("div", { className: "space-y-2 text-center", children: [
|
|
227
227
|
/* @__PURE__ */ jsx5("p", { className: "text-base text-[var(--color-neutral-700)]", children: "The Spotify app is in development mode, so only allowlisted accounts can connect." }),
|
|
228
228
|
requestAccessHref && contactEmail ? /* @__PURE__ */ jsxs5("p", { className: "text-base text-[var(--color-neutral-700)]", children: [
|
|
@@ -274,4 +274,4 @@ export {
|
|
|
274
274
|
AuthPopup,
|
|
275
275
|
SpotifyAuthErrorPopup
|
|
276
276
|
};
|
|
277
|
-
//# sourceMappingURL=chunk-
|
|
277
|
+
//# sourceMappingURL=chunk-NJYEQ3RS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/popup/TrackUploadPopup.tsx","../src/popup/AuthErrorPopup.tsx","../src/popup/NetworkErrorPopup.tsx","../src/popup/AuthPopup.tsx","../src/popup/SpotifyAuthErrorPopup.tsx"],"sourcesContent":["\"use client\";\n\nimport { MdError, MdCheckCircle, MdUpload } from \"react-icons/md\";\nimport { useTrackUpload, type UploadStatus, type UseTrackUploadOptions } from \"@behindthemusictree/app-kit/popup\";\nimport { BasePopup, BasePopupProps } from \"./BasePopup\";\nimport { capitalize, useTrackNoun } from \"@behindthemusictree/app-kit/track-noun\";\n\ntype TrackUploadPopupProps = Omit<BasePopupProps, \"title\" | \"children\" | \"icon\" | \"isDismissable\"> &\n UseTrackUploadOptions & {\n onClose?: () => void;\n };\n\nfunction getStatusIcon(status: UploadStatus) {\n switch (status) {\n case \"success\":\n return <MdCheckCircle className=\"text-[var(--color-green-500)]\" size={20} />;\n case \"error\":\n return <MdError className=\"text-[var(--color-red-500)]\" size={20} />;\n case \"uploading\":\n return <MdUpload className=\"text-[var(--color-blue-500)] animate-pulse\" size={20} />;\n default:\n return <div className=\"w-5 h-5 rounded-full border-2 border-[var(--color-neutral-300)]\" />;\n }\n}\n\nfunction getStatusText(status: UploadStatus) {\n switch (status) {\n case \"success\":\n return \"Uploaded\";\n case \"error\":\n return \"Failed\";\n case \"uploading\":\n return \"Uploading...\";\n default:\n return \"Pending\";\n }\n}\n\nexport default function TrackUploadPopup({\n files,\n genre,\n onProcessFile,\n onComplete,\n onClose,\n uploadTimeoutMs,\n ...rest\n}: TrackUploadPopupProps) {\n const { items, isUploading, allComplete, successfulCount, errorCount } = useTrackUpload({\n files,\n genre,\n onProcessFile,\n onComplete,\n uploadTimeoutMs,\n });\n\n const displayTotal = items.length > 0 ? items.length : files.length;\n const trackNoun = useTrackNoun();\n\n return (\n <BasePopup\n {...rest}\n onClose={onClose}\n title={`Upload ${capitalize(trackNoun.plural)} (${successfulCount}/${displayTotal})`}\n isDismissable\n showOkButton\n okButtonText=\"OK\"\n okButtonDisabled={isUploading || !allComplete}\n onOk={onClose}\n >\n <div className=\"space-y-4\">\n {items.map((item) => (\n <div key={item.id} className=\"border rounded-lg p-4\">\n <div className=\"flex items-center justify-between mb-2\">\n <div className=\"flex items-center space-x-3\">\n {getStatusIcon(item.status)}\n <div>\n <div className=\"font-medium text-body truncate max-w-xs\" title={item.file.name}>\n {item.file.name}\n </div>\n <div className=\"text-caption text-[var(--color-neutral-500)]\">{(item.file.size / 1024 / 1024).toFixed(1)} MB</div>\n </div>\n </div>\n <div className=\"text-body text-[var(--color-neutral-600)]\">{getStatusText(item.status)}</div>\n </div>\n\n {item.status === \"uploading\" && (\n <div className=\"w-full bg-[var(--color-neutral-200)] rounded-full h-2\">\n <div\n className=\"bg-[var(--color-blue-500)] h-2 rounded-full transition-all duration-300\"\n style={{ width: `${item.progress}%` }}\n />\n </div>\n )}\n\n {item.status === \"error\" && item.error && (\n <div className=\"text-[var(--color-red-500)] text-body mt-2\">\n {item.error.name === \"InvalidInputError\"\n ? \"Upload failed due to invalid file data. Please check your file and try again.\"\n : item.error.name === \"ZodError\"\n ? \"Upload failed due to a server error. Please try again later.\"\n : item.error.message}\n </div>\n )}\n </div>\n ))}\n\n {allComplete && (\n <div className=\"flex justify-between items-center\">\n <div className=\"text-body text-[var(--color-neutral-600)]\">\n {successfulCount} successful, {errorCount} failed\n </div>\n </div>\n )}\n </div>\n </BasePopup>\n );\n}\n","\"use client\";\n\nimport { AlertCircle } from \"lucide-react\";\nimport { BasePopup, BasePopupProps } from \"./BasePopup\";\nimport { Button } from \"@behindthemusictree/ui\";\n\ntype AuthErrorPopupProps = Omit<BasePopupProps, \"title\" | \"children\" | \"icon\" | \"isDismissable\"> & {\n message: string;\n onClose: () => void;\n};\n\nexport default function AuthErrorPopup({ message, onClose, ...rest }: AuthErrorPopupProps) {\n return (\n <BasePopup\n {...rest}\n title=\"Sign-in error\"\n isDismissable\n icon={AlertCircle}\n children={\n <div className=\"flex flex-col items-center space-y-6 py-4\">\n <p className=\"text-center text-lg font-medium text-[var(--color-text)]\">{message}</p>\n <Button onClick={onClose} variant=\"secondary\" className=\"w-full max-w-xs\">\n Close\n </Button>\n </div>\n }\n />\n );\n}\n","\"use client\";\n\nimport { AlertTriangle } from \"lucide-react\";\nimport { BasePopup, BasePopupProps } from \"./BasePopup\";\nimport { ErrorCode } from \"@behindthemusictree/app-kit/transport\";\n\ntype NetworkErrorPopupProps = Omit<BasePopupProps, \"title\" | \"children\" | \"icon\" | \"isDismissable\"> & {\n errorCode: ErrorCode;\n};\n\nconst OFFLINE_MESSAGE = \"It seems that you are not connected to the internet. Please check your connection and try again.\";\nconst UNREACHABLE_MESSAGE = \"We couldn't reach the server. Please try again in a moment.\";\n\nexport default function NetworkErrorPopup({ errorCode, ...rest }: NetworkErrorPopupProps) {\n return (\n <BasePopup\n {...rest}\n title=\"Network Error\"\n isDismissable={false}\n icon={AlertTriangle}\n children={\n <div className=\"flex flex-col items-center space-y-6 py-4\">\n <AlertTriangle className=\"h-16 w-16 text-[var(--color-neutral-600)]\" strokeWidth={1.5} />\n <p className=\"text-center text-[var(--color-neutral-700)]\">\n {errorCode === ErrorCode.NETWORK_OFFLINE ? OFFLINE_MESSAGE : UNREACHABLE_MESSAGE}\n </p>\n </div>\n }\n />\n );\n}\n","\"use client\";\n\nimport { ReactNode } from \"react\";\nimport { User } from \"lucide-react\";\nimport { BasePopup, BasePopupProps } from \"./BasePopup\";\nimport { Button } from \"@behindthemusictree/ui\";\nimport { FaSpotify } from \"react-icons/fa\";\nimport { FcGoogle } from \"react-icons/fc\";\n\ntype AuthPopupProps = Omit<BasePopupProps, \"title\" | \"children\" | \"icon\" | \"isDismissable\"> & {\n handleSpotifyOAuth: (redirectAfterAuthPath?: string) => void;\n handleGoogleOAuth?: (redirectAfterAuthPath?: string) => void;\n redirectAfterAuthPath?: string;\n spotifyOnly?: boolean;\n message?: string;\n /**\n * Body copy shown when `spotifyOnly` is true. Wording (app name, feature description) is\n * app-specific, so each consuming app supplies its own instead of this package assuming one.\n */\n spotifyOnlyDescription: ReactNode;\n /** Body copy shown when `spotifyOnly` is false, for the same reason as `spotifyOnlyDescription`. */\n defaultDescription: ReactNode;\n};\n\nexport default function AuthPopup({\n handleSpotifyOAuth,\n handleGoogleOAuth,\n redirectAfterAuthPath,\n spotifyOnly,\n message,\n spotifyOnlyDescription,\n defaultDescription,\n ...rest\n}: AuthPopupProps) {\n const showGoogle = !spotifyOnly && handleGoogleOAuth;\n\n return (\n <BasePopup\n {...rest}\n title={spotifyOnly ? \"Connect with Spotify\" : \"Sign in\"}\n isDismissable={false}\n icon={User}\n type=\"auth\"\n children={\n <div className=\"flex flex-col items-center space-y-7\">\n <div className=\"px-2 text-center\">\n {message && <p className=\"mb-3 text-base font-medium leading-relaxed text-amber-200\">{message}</p>}\n <p className=\"text-lg font-medium leading-relaxed text-white\">\n {spotifyOnly ? spotifyOnlyDescription : defaultDescription}\n </p>\n </div>\n <div className=\"flex w-full flex-col items-center gap-3\">\n <Button\n onClick={() => handleSpotifyOAuth(redirectAfterAuthPath)}\n className=\"relative mb-2 w-fit transform bg-green-600 px-8 py-3 text-white shadow-lg transition-all duration-200 hover:scale-[1.02] hover:bg-green-700 hover:shadow-xl\"\n >\n <span className=\"flex items-center justify-center\">\n <FaSpotify className=\"absolute left-6 text-3xl\" />\n <span className=\"w-full pl-14 pr-8 text-center text-lg font-medium\">Sign in with Spotify</span>\n </span>\n </Button>\n {showGoogle && (\n <Button\n variant=\"outline\"\n onClick={() => handleGoogleOAuth!(redirectAfterAuthPath)}\n className=\"relative w-fit transform border-white bg-white px-8 py-3 text-black shadow-lg transition-all duration-200 hover:scale-[1.02] hover:bg-[var(--color-neutral-100)] hover:shadow-xl\"\n >\n <span className=\"flex items-center justify-center\">\n <FcGoogle className=\"absolute left-6 text-2xl\" />\n <span className=\"w-full pl-14 pr-8 text-center text-lg font-medium text-black\">\n Sign in with Google\n </span>\n </span>\n </Button>\n )}\n </div>\n </div>\n }\n />\n );\n}\n","\"use client\";\n\nimport { FaSpotify } from \"react-icons/fa\";\nimport { BasePopup, BasePopupProps } from \"./BasePopup\";\nimport { Button } from \"@behindthemusictree/ui\";\nimport { User } from \"lucide-react\";\nimport { getSpotifyAllowlistMailtoHref } from \"@behindthemusictree/app-kit/transport\";\n\ntype SpotifyAuthErrorPopupProps = Omit<BasePopupProps, \"title\" | \"children\" | \"icon\" | \"isDismissable\"> & {\n message: string;\n details?: string;\n onClose: () => void;\n /**\n * Support contact email used to build the allowlist-request mailto link. 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 SpotifyAuthErrorPopup({\n message,\n details,\n onClose,\n contactEmail = null,\n ...rest\n}: SpotifyAuthErrorPopupProps) {\n const requestAccessHref = getSpotifyAllowlistMailtoHref(contactEmail);\n\n return (\n <BasePopup\n {...rest}\n title=\"Authentication Failed\"\n isDismissable\n icon={User}\n children={\n <div className=\"flex flex-col items-center space-y-8 py-4\">\n <FaSpotify className=\"text-[#1DB954] text-7xl\" />\n <div className=\"space-y-3 text-center\">\n <p className=\"text-xl font-medium text-[var(--color-text)]\">{message}</p>\n {details && (\n <p className=\"text-body text-[var(--color-neutral-500)] bg-[var(--color-neutral-100)] p-3 rounded-lg border border-[var(--color-neutral-100)]\">{details}</p>\n )}\n <div className=\"space-y-2 text-center\">\n <p className=\"text-base text-[var(--color-neutral-700)]\">\n The Spotify app is in development mode, so only allowlisted accounts can connect.\n </p>\n {requestAccessHref && contactEmail ? (\n <p className=\"text-base text-[var(--color-neutral-700)]\">\n Request access by emailing your{\" \"}\n <a\n href={requestAccessHref}\n className=\"text-[#1DB954] font-medium underline hover:no-underline focus:outline-none focus:ring-2 focus:ring-[#1DB954] focus:ring-offset-1 rounded\"\n >\n Spotify full name and Spotify email address\n </a>{\" \"}\n to{\" \"}\n <a\n href={requestAccessHref}\n className=\"text-[#1DB954] font-medium underline hover:no-underline focus:outline-none focus:ring-2 focus:ring-[#1DB954] focus:ring-offset-1 rounded\"\n >\n {contactEmail}\n </a>\n .\n </p>\n ) : (\n <p className=\"text-base text-[var(--color-neutral-700)]\">To request access, contact the app owner.</p>\n )}\n </div>\n </div>\n <Button\n onClick={onClose}\n className=\"bg-[#1DB954] hover:bg-[#1DB954]/90 text-white w-full max-w-xs transform transition-all duration-200 hover:scale-[1.02] shadow-lg hover:shadow-xl\"\n >\n <FaSpotify className=\"mr-2 text-lg\" />\n Try Again\n </Button>\n </div>\n }\n />\n );\n}\n"],"mappings":"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","names":["jsx","jsxs","jsx","jsxs","Button","jsx","jsxs","FaSpotify","Button","User","jsx","jsxs","FaSpotify"]}
|
|
@@ -296,7 +296,7 @@ function InternalErrorPopup({ errorCode, contactEmail, ...rest }) {
|
|
|
296
296
|
" ",
|
|
297
297
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("a", { href: `mailto:${contactEmail}`, className: "text-[var(--color-primary)] hover:text-[var(--color-primary-hover)]", children: contactEmail })
|
|
298
298
|
] }) }),
|
|
299
|
-
errorCode && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "text-
|
|
299
|
+
errorCode && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("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: [
|
|
300
300
|
"Error Code: ",
|
|
301
301
|
errorCode
|
|
302
302
|
] })
|
|
@@ -786,7 +786,7 @@ function useArtistSearchGroup(getBaseUrl, text, onSelect, enabled = true) {
|
|
|
786
786
|
artist.disambiguation
|
|
787
787
|
] })
|
|
788
788
|
] }),
|
|
789
|
-
artist.matchedAlias && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "block truncate text-
|
|
789
|
+
artist.matchedAlias && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "block truncate text-caption text-[var(--color-neutral-500)]", children: [
|
|
790
790
|
"also known as ",
|
|
791
791
|
artist.matchedAlias
|
|
792
792
|
] })
|
|
@@ -811,7 +811,7 @@ function useSongSearchGroup(getBaseUrl, text, onSelect, enabled = true) {
|
|
|
811
811
|
key: song.uuid,
|
|
812
812
|
content: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: (0, import_genre_tree7.isSongSearchResultPlayable)(song) ? void 0 : "opacity-60", children: [
|
|
813
813
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "block truncate font-medium", children: song.title }),
|
|
814
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "block truncate text-
|
|
814
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("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 ") })
|
|
815
815
|
] }),
|
|
816
816
|
onSelect: () => onSelect(song)
|
|
817
817
|
})),
|
|
@@ -834,9 +834,9 @@ function useGenreRemoteSearchGroup(getBaseUrl, text, onSelect, { key = "genres",
|
|
|
834
834
|
content: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
835
835
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "block truncate font-medium", children: [
|
|
836
836
|
genre.name,
|
|
837
|
-
genre.isUmbrella && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "ml-2 text-
|
|
837
|
+
genre.isUmbrella && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "ml-2 text-caption font-normal italic text-[var(--color-text-muted)]", children: "umbrella" })
|
|
838
838
|
] }),
|
|
839
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "block truncate text-
|
|
839
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "block truncate text-caption text-[var(--color-neutral-500)]", children: describe?.(genre) ?? `${genre.treeName} \xB7 ${genre.root.name}` })
|
|
840
840
|
] }),
|
|
841
841
|
onSelect: () => onSelect(genre)
|
|
842
842
|
})),
|
|
@@ -877,7 +877,7 @@ function GenreSearch({
|
|
|
877
877
|
key: genrePlaylist.uuid,
|
|
878
878
|
content: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
|
|
879
879
|
genrePlaylist.name,
|
|
880
|
-
genrePlaylist.isUmbrella && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "ml-2 text-
|
|
880
|
+
genrePlaylist.isUmbrella && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "ml-2 text-caption italic text-[var(--color-text-muted)]", children: "umbrella" })
|
|
881
881
|
] }),
|
|
882
882
|
onSelect: () => select(genrePlaylist)
|
|
883
883
|
}))
|
|
@@ -995,7 +995,7 @@ function Toast({ message, onClose, durationMs = 2200 }) {
|
|
|
995
995
|
role: "status",
|
|
996
996
|
"aria-live": "polite",
|
|
997
997
|
"aria-atomic": "true",
|
|
998
|
-
className: "pointer-events-auto w-full max-w-md rounded-md bg-[var(--color-surface)] px-4 py-4 text-
|
|
998
|
+
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",
|
|
999
999
|
children: message
|
|
1000
1000
|
}
|
|
1001
1001
|
) }),
|
|
@@ -1005,7 +1005,7 @@ function Toast({ message, onClose, durationMs = 2200 }) {
|
|
|
1005
1005
|
|
|
1006
1006
|
// src/genre-tree/ShareDestinationButton.tsx
|
|
1007
1007
|
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
1008
|
-
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-
|
|
1008
|
+
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";
|
|
1009
1009
|
function Contents({ icon, label }) {
|
|
1010
1010
|
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
|
|
1011
1011
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("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 }),
|
|
@@ -1035,9 +1035,9 @@ function SharePreviewCard({ target, url }) {
|
|
|
1035
1035
|
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "rounded-3xl bg-[var(--color-surface-muted)] p-4", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex min-h-32 overflow-hidden rounded-2xl bg-[var(--color-surface)] shadow-lg", children: [
|
|
1036
1036
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "flex w-28 shrink-0 items-center justify-center bg-[var(--color-primary)]/15 text-[var(--color-primary)]", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Icon, { "aria-hidden": "true", className: "h-10 w-10" }) }),
|
|
1037
1037
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col justify-center gap-1 p-4", children: [
|
|
1038
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "text-
|
|
1038
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "text-caption font-medium uppercase tracking-wide text-[var(--color-text-muted)]", children: typeLabel }),
|
|
1039
1039
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "truncate text-base font-semibold text-[var(--color-text)]", title: target.name, children: target.name }),
|
|
1040
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "truncate text-
|
|
1040
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "truncate text-body text-[var(--color-primary)]", title: url, children: url })
|
|
1041
1041
|
] })
|
|
1042
1042
|
] }) });
|
|
1043
1043
|
}
|
|
@@ -1178,8 +1178,8 @@ function SharePopup({ target, url, onClose }) {
|
|
|
1178
1178
|
}
|
|
1179
1179
|
)
|
|
1180
1180
|
] }),
|
|
1181
|
-
copyStatus === "failed" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { role: "alert", className: "text-center text-
|
|
1182
|
-
shareError && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { role: "alert", className: "text-center text-
|
|
1181
|
+
copyStatus === "failed" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { role: "alert", className: "text-center text-body text-[var(--color-red-500)]", children: "Could not copy the link." }),
|
|
1182
|
+
shareError && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { role: "alert", className: "text-center text-body text-[var(--color-red-500)]", children: shareError })
|
|
1183
1183
|
] })
|
|
1184
1184
|
}
|
|
1185
1185
|
),
|
|
@@ -1199,7 +1199,7 @@ function ShareActionButton({ target, url }) {
|
|
|
1199
1199
|
{
|
|
1200
1200
|
type: "button",
|
|
1201
1201
|
onClick: openSharePopup,
|
|
1202
|
-
className: "group flex flex-col items-center gap-1 w-16 text-
|
|
1202
|
+
className: "group flex flex-col items-center gap-1 w-16 text-caption text-center text-[var(--color-text)] focus-visible:outline-none",
|
|
1203
1203
|
"aria-label": `Share ${target.name}`,
|
|
1204
1204
|
title: `Share ${target.name}`,
|
|
1205
1205
|
children: [
|
|
@@ -1281,7 +1281,7 @@ function GenreActionBand({
|
|
|
1281
1281
|
disabled: item.disabled,
|
|
1282
1282
|
title: item.title,
|
|
1283
1283
|
onClick: item.onClick,
|
|
1284
|
-
className: "group flex flex-col items-center gap-1 w-16 text-
|
|
1284
|
+
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",
|
|
1285
1285
|
children: [
|
|
1286
1286
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("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 }),
|
|
1287
1287
|
item.label
|
|
@@ -1300,7 +1300,7 @@ function GenreActionBand({
|
|
|
1300
1300
|
"aria-label": "Admin actions",
|
|
1301
1301
|
className: `px-3.5 py-3 ${items.length > 0 ? "border-t border-[var(--color-border)]" : ""}`,
|
|
1302
1302
|
children: [
|
|
1303
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("h3", { className: "mb-2 text-
|
|
1303
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("h3", { className: "mb-2 text-caption font-semibold uppercase tracking-wide text-[var(--color-text-muted)]", children: "Admin" }),
|
|
1304
1304
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex flex-wrap gap-1", children: renderItems(adminItems) })
|
|
1305
1305
|
]
|
|
1306
1306
|
}
|
|
@@ -1332,7 +1332,7 @@ function ClampedText({ children, className: className2 = "" }) {
|
|
|
1332
1332
|
type: "button",
|
|
1333
1333
|
"aria-expanded": expanded,
|
|
1334
1334
|
onClick: () => setExpanded((value) => !value),
|
|
1335
|
-
className: "mt-1 text-
|
|
1335
|
+
className: "mt-1 text-caption text-[var(--color-text-muted)] underline hover:text-[var(--color-text)]",
|
|
1336
1336
|
children: expanded ? "Show less" : "Show more"
|
|
1337
1337
|
}
|
|
1338
1338
|
)
|
|
@@ -1483,7 +1483,7 @@ function GenrePlaylistTracks({
|
|
|
1483
1483
|
".",
|
|
1484
1484
|
" ",
|
|
1485
1485
|
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { type: "button", className: "underline", onClick: () => void refetch(), children: "Retry" })
|
|
1486
|
-
] }) : tracks.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { children: "\u2014" }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("ul", { className: "mt-1 max-h-64 overflow-y-auto text-
|
|
1486
|
+
] }) : tracks.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { children: "\u2014" }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("ul", { className: "mt-1 max-h-64 overflow-y-auto text-body [container-type:inline-size]", "aria-label": `${genreName} ${trackNoun.plural}`, children: [
|
|
1487
1487
|
tracks.map((track, index) => {
|
|
1488
1488
|
const label = track.artists?.length ? `${track.title} \u2014 ${track.artists.map((artist2) => artist2.name).join(", ")}` : track.title;
|
|
1489
1489
|
const isCurrent = playerTrackObject?.track.id === track.uuid;
|
|
@@ -1581,7 +1581,7 @@ function GenreDetailExtras({
|
|
|
1581
1581
|
const { summary, summarySourceUrl, essentialSongs } = overview;
|
|
1582
1582
|
const wikidataUrl = wikidataId ? `https://www.wikidata.org/wiki/${encodeURIComponent(wikidataId)}` : null;
|
|
1583
1583
|
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
|
|
1584
|
-
(summarySourceUrl || wikidataUrl) && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_ui6.PanelSection, { title: "Links", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex flex-wrap gap-x-3 gap-y-1 text-
|
|
1584
|
+
(summarySourceUrl || wikidataUrl) && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_ui6.PanelSection, { title: "Links", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex flex-wrap gap-x-3 gap-y-1 text-caption text-[var(--color-text)]", children: [
|
|
1585
1585
|
summarySourceUrl && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
1586
1586
|
"a",
|
|
1587
1587
|
{
|
|
@@ -1609,10 +1609,10 @@ function GenreDetailExtras({
|
|
|
1609
1609
|
}
|
|
1610
1610
|
)
|
|
1611
1611
|
] }) }),
|
|
1612
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_ui6.PanelSection, { title: "Summary", children: renderSummary ? renderSummary(overview) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ClampedText, { className: "text-
|
|
1612
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_ui6.PanelSection, { title: "Summary", children: renderSummary ? renderSummary(overview) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ClampedText, { className: "text-body text-[var(--color-text)]", children: summary ?? "\u2014" }, genreUuid) }),
|
|
1613
1613
|
family,
|
|
1614
1614
|
renderGenreDetailExtras?.(overview),
|
|
1615
|
-
(renderEssentialTracks || essentialSongs) && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_ui6.PanelSection, { title: `Essential ${trackNoun.plural}`, children: renderEssentialTracks ? renderEssentialTracks(overview) : essentialSongs && essentialSongs.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("ul", { className: "text-
|
|
1615
|
+
(renderEssentialTracks || essentialSongs) && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_ui6.PanelSection, { title: `Essential ${trackNoun.plural}`, children: renderEssentialTracks ? renderEssentialTracks(overview) : essentialSongs && essentialSongs.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("ul", { className: "text-body text-[var(--color-text)]", children: essentialSongs.map((track) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("li", { className: "py-1", children: track.title }, track.uuid)) }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "text-body text-[var(--color-text)]", children: "\u2014" }) }),
|
|
1616
1616
|
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
1617
1617
|
GenrePlaylistTracks,
|
|
1618
1618
|
{
|
|
@@ -1678,7 +1678,7 @@ function GenreInfoPanelBody({
|
|
|
1678
1678
|
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
|
|
1679
1679
|
toolbar,
|
|
1680
1680
|
genrePlaylist ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GenreNodeActionBand, { ...band, genrePlaylist, playback }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GenreActionBand, { ...band }),
|
|
1681
|
-
summary && catalogue && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "px-3.5 py-3 text-
|
|
1681
|
+
summary && catalogue && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "px-3.5 py-3 text-body text-[var(--color-text)]", children: [
|
|
1682
1682
|
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("p", { children: [
|
|
1683
1683
|
"Catalogue ",
|
|
1684
1684
|
noun.plural,
|
|
@@ -1768,7 +1768,7 @@ function useGenreDetailContent({
|
|
|
1768
1768
|
if (isError) return {
|
|
1769
1769
|
name: null,
|
|
1770
1770
|
title: "Genre unavailable",
|
|
1771
|
-
content: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { role: "alert", className: "p-4 text-
|
|
1771
|
+
content: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { role: "alert", className: "p-4 text-body text-[var(--color-text)]", children: "This genre could not be loaded." })
|
|
1772
1772
|
};
|
|
1773
1773
|
if (isPending || !detail || !view) return {
|
|
1774
1774
|
name: null,
|
|
@@ -1904,7 +1904,7 @@ function ChangeParentPopup({
|
|
|
1904
1904
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
1905
1905
|
}, [onClose]);
|
|
1906
1906
|
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(BasePopup_default, { title: `Change parent of ${genrePlaylist.name}`, onClose, showCancelButton: true, fitContent: true, children: [
|
|
1907
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("p", { className: "mb-3 text-
|
|
1907
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("p", { className: "mb-3 text-body text-[var(--color-text-muted)]", children: [
|
|
1908
1908
|
"Current parent: ",
|
|
1909
1909
|
genrePlaylist.parent?.name ?? "none"
|
|
1910
1910
|
] }),
|
|
@@ -1916,7 +1916,7 @@ function ChangeParentPopup({
|
|
|
1916
1916
|
placeholder: "Search a new parent\u2026"
|
|
1917
1917
|
}
|
|
1918
1918
|
) }),
|
|
1919
|
-
formErrors.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { role: "alert", className: "mt-3 text-
|
|
1919
|
+
formErrors.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { role: "alert", className: "mt-3 text-body text-[var(--color-red-500)]", children: formErrors.map(({ message }) => message).join(" ") })
|
|
1920
1920
|
] });
|
|
1921
1921
|
}
|
|
1922
1922
|
|
|
@@ -2002,7 +2002,7 @@ function ExternalLink({ href, children }) {
|
|
|
2002
2002
|
function ArtistPhoto({ image, name }) {
|
|
2003
2003
|
return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("figure", { className: "flex flex-col gap-1.5 px-6 py-2.5", children: [
|
|
2004
2004
|
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("img", { src: image.url, alt: name, className: "h-64 w-full object-contain bg-[var(--color-surface-muted)] rounded" }),
|
|
2005
|
-
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("figcaption", { className: "text-
|
|
2005
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("figcaption", { className: "text-caption text-[var(--color-text-muted)]", children: [
|
|
2006
2006
|
"Photo: ",
|
|
2007
2007
|
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ExternalLink, { href: image.pageUrl, children: image.author ?? "Wikimedia Commons" }),
|
|
2008
2008
|
",",
|
|
@@ -2201,7 +2201,7 @@ function TrackItem({
|
|
|
2201
2201
|
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "flex max-w-full items-center gap-2", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "title text-lg font-bold text-[var(--color-text)] max-w-full truncate", children: renderSongLink ? renderSongLink(track) : (0, import_genre_tree22.isSong)(track) ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(MusicBrainzRecordingLink, { song: track, className: "hover:underline focus-visible:underline", children: track.title }) : track.title }) }),
|
|
2202
2202
|
track.artists && track.artists.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "artist text-base max-w-full truncate text-[var(--color-text-muted)]", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_genre_tree23.ArtistNames, { artists: track.artists, renderArtistLink }) }) : ""
|
|
2203
2203
|
] }),
|
|
2204
|
-
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "genre-name-container flex items-center justify-start w-[21.6%] min-w-0 shrink-0", children: track.genre ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "genre-name max-w-full whitespace-normal break-words p-1 text-
|
|
2204
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "genre-name-container flex items-center justify-start w-[21.6%] min-w-0 shrink-0", children: track.genre ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "genre-name max-w-full whitespace-normal break-words p-1 text-caption font-bold", children: track.genre.name }) : "" }),
|
|
2205
2205
|
renderDuration && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2206
2206
|
"div",
|
|
2207
2207
|
{
|
|
@@ -2257,14 +2257,14 @@ function ArtistSongs({ artist, getBackendBaseUrl, renderArtistLink, renderSongLi
|
|
|
2257
2257
|
{
|
|
2258
2258
|
type: "button",
|
|
2259
2259
|
onClick: () => void play(),
|
|
2260
|
-
className: "flex w-fit items-center gap-1.5 px-3 py-1 text-
|
|
2260
|
+
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",
|
|
2261
2261
|
children: [
|
|
2262
2262
|
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_lucide_react10.Play, { className: "h-3.5 w-3.5", "aria-hidden": "true" }),
|
|
2263
2263
|
"Play all"
|
|
2264
2264
|
]
|
|
2265
2265
|
}
|
|
2266
2266
|
),
|
|
2267
|
-
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { role: "group", "aria-label": "Sort songs by", className: "flex gap-1 text-
|
|
2267
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { role: "group", "aria-label": "Sort songs by", className: "flex gap-1 text-caption", children: SORTS.map((sort) => /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
2268
2268
|
"button",
|
|
2269
2269
|
{
|
|
2270
2270
|
type: "button",
|
|
@@ -2385,7 +2385,7 @@ function SongHistory({ uuid, getBackendBaseUrl }) {
|
|
|
2385
2385
|
if (history.status === "loading") body = /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_ui14.Skeleton, { className: "h-10", "aria-busy": "true" });
|
|
2386
2386
|
else if (history.status === "error") body = /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { className: "text-red-600", children: "Could not load the history." });
|
|
2387
2387
|
else if (history.status === "success")
|
|
2388
|
-
body = history.entries.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "No changes yet." }) : /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("ul", { className: "divide-y divide-[var(--color-border)]", children: history.entries.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("li", { className: "py-1.5 text-
|
|
2388
|
+
body = history.entries.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { className: "text-[var(--color-text-muted)]", children: "No changes yet." }) : /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("ul", { className: "divide-y divide-[var(--color-border)]", children: history.entries.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("li", { className: "py-1.5 text-body", children: [
|
|
2389
2389
|
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "font-medium", children: entry.action }),
|
|
2390
2390
|
entry.oldValue !== null || entry.newValue !== null ? /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("span", { className: "text-[var(--color-text-muted)]", children: [
|
|
2391
2391
|
" ",
|
|
@@ -2394,7 +2394,7 @@ function SongHistory({ uuid, getBackendBaseUrl }) {
|
|
|
2394
2394
|
" \u2192 ",
|
|
2395
2395
|
entry.newValue ?? "none"
|
|
2396
2396
|
] }) : null,
|
|
2397
|
-
/* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("span", { className: "block text-
|
|
2397
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("span", { className: "block text-caption text-[var(--color-text-muted)]", children: [
|
|
2398
2398
|
entry.actorPseudo ?? "Anonymous",
|
|
2399
2399
|
" \xB7 ",
|
|
2400
2400
|
dateFormat.format(new Date(entry.createdOn))
|
|
@@ -2467,12 +2467,12 @@ function SongPanelContent(props) {
|
|
|
2467
2467
|
});
|
|
2468
2468
|
return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_jsx_runtime37.Fragment, { children: [
|
|
2469
2469
|
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "genre-action-band border-b border-[var(--color-border)]", children: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "flex flex-wrap gap-1 px-3.5 py-3", children: [
|
|
2470
|
-
unplayableReason ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { className: "flex items-center px-2.5 text-
|
|
2470
|
+
unplayableReason ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { className: "flex items-center px-2.5 text-body text-[var(--color-text-muted)]", children: unplayableReason }) : /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
|
|
2471
2471
|
"button",
|
|
2472
2472
|
{
|
|
2473
2473
|
type: "button",
|
|
2474
2474
|
onClick: () => isCurrent ? handlePlayPauseAction() : playNewTrackListFromTrackUuid(song, scope),
|
|
2475
|
-
className: "group flex flex-col items-center gap-1 w-16 text-
|
|
2475
|
+
className: "group flex flex-col items-center gap-1 w-16 text-caption text-center text-[var(--color-text)] focus-visible:outline-none",
|
|
2476
2476
|
children: [
|
|
2477
2477
|
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("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__ */ (0, import_jsx_runtime37.jsx)(import_lucide_react11.Pause, { "aria-hidden": "true", className: "w-5 h-5" }) : /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_lucide_react11.Play, { "aria-hidden": "true", className: "w-5 h-5" }) }),
|
|
2478
2478
|
isPlaying ? "Pause" : "Play"
|
|
@@ -2980,7 +2980,7 @@ function GenreTreeView({
|
|
|
2980
2980
|
) : null;
|
|
2981
2981
|
const renderArtistFilter = () => {
|
|
2982
2982
|
if (isLoading || !filterArtist) return null;
|
|
2983
|
-
return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("span", { className: "inline-flex items-center overflow-hidden rounded-full bg-[var(--color-neutral-100)] text-
|
|
2983
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("span", { className: "inline-flex items-center overflow-hidden rounded-full bg-[var(--color-neutral-100)] text-body", children: [
|
|
2984
2984
|
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
2985
2985
|
"button",
|
|
2986
2986
|
{
|
|
@@ -3091,14 +3091,14 @@ function GenreTreeView({
|
|
|
3091
3091
|
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
3092
3092
|
"div",
|
|
3093
3093
|
{
|
|
3094
|
-
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"}`,
|
|
3094
|
+
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"}`,
|
|
3095
3095
|
children: actions
|
|
3096
3096
|
}
|
|
3097
3097
|
),
|
|
3098
3098
|
!isLoading && !isError && filterArtist && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
3099
3099
|
"div",
|
|
3100
3100
|
{
|
|
3101
|
-
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"}`,
|
|
3101
|
+
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"}`,
|
|
3102
3102
|
children: renderArtistFilter()
|
|
3103
3103
|
}
|
|
3104
3104
|
),
|
|
@@ -3368,7 +3368,7 @@ function TrackListSidebar({
|
|
|
3368
3368
|
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "from h-auto flex flex-col justify-center items-center mr-2", children: "From" }),
|
|
3369
3369
|
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "name-container flex flex-col justify-center items-center text-[var(--color-text)] font-bold pr-2 max-w-[27.5rem]", children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "name max-w-full truncate", children: trackList.origin.label }) })
|
|
3370
3370
|
] }),
|
|
3371
|
-
/* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "info flex items-center text-
|
|
3371
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "info flex items-center text-body text-[var(--color-text-muted)]", children: [
|
|
3372
3372
|
trackList.origin.type === import_genre_tree30.TrackListOriginType.GENRE_PLAYLIST ? "Genre \u2022 " : trackList.origin.type === import_genre_tree30.TrackListOriginType.ARTIST ? "Artist \u2022 " : `${trackNoun.singular} playlist \u2022 `,
|
|
3373
3373
|
`${trackList.total} ${trackList.total > 1 ? trackNoun.plural : trackNoun.singular}`
|
|
3374
3374
|
] })
|