1import { r as reactExports, j as jsxRuntimeExports } from "./vendor-react-Bay9Y7Lb.js"; 2import { a as api } from "./index-w5lXls15.js"; 3import { u as useTranslation } from "./vendor-i18n-BC7ZMXWQ.js"; 4import { bB as ListMusic, cf as Plus, bV as Play, b$ as EllipsisVertical } from "./vendor-D0P4XgNj.js"; 5const PlaylistsPage = ({ currentUser, onAuthRequested }) => { 6 const { t } = useTranslation(); 7 const [playlists, setPlaylists] = reactExports.useState([]); 8 const [loading, setLoading] = reactExports.useState(true); 9 const [isCreating, setIsCreating] = reactExports.useState(false); 10 const [newTitle, setNewTitle] = reactExports.useState(""); 11 const [isPublic, setIsPublic] = reactExports.useState(false); 12 reactExports.useEffect(() => { 13 if (currentUser) { 14 api.getPlaylists(currentUser.id).then((data) => { 15 setPlaylists(data); 16 setLoading(false); 17 }); 18 } else { 19 setLoading(false); 20 } 21 }, [currentUser]); 22 const handleCreate = async () => { 23 if (!newTitle.trim() || !currentUser) return; 24 const pl = await api.createPlaylist(currentUser.id, newTitle, isPublic); 25 setPlaylists([...playlists, pl]); 26 setNewTitle(""); 27 setIsPublic(false); 28 setIsCreating(false); 29 }; 30 if (!currentUser) { 31 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center justify-center h-[60vh] text-center p-6", children: [
32 /* @__PURE__ */ jsxRuntimeExports.jsx(ListMusic, { size: 48, className: "text-zinc-300 dark:text-zinc-700 mb-4" }), 33 /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-xl font-bold text-zinc-900 dark:text-white mb-2", children: t("playlists.title", "Playlists") }), 34 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-zinc-500 mb-6", children: t("playlists.signInPrompt", "Sign in to create and manage playlists.") }), 35 /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onAuthRequested, className: "px-6 py-2 bg-indigo-600 hover:bg-indigo-700 text-white rounded-full font-bold transition-colors", children: t("common.signIn", "Sign In") }) 36 ] }); 37 } 38 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-6 max-w-5xl mx-auto min-h-[80vh] animate-in fade-in", children: [ 39 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center mb-8", children: [ 40 /* @__PURE__ */ jsxRuntimeExports.jsxs("h1", { className: "text-3xl font-bold text-zinc-900 dark:text-white flex items-center gap-3", children: [
41 /* @__PURE__ */ jsxRuntimeExports.jsx(ListMusic, { className: "text-indigo-500" }), 42 " ", 43 t("playlists.title", "Playlists") 44 ] }), 45 /* @__PURE__ */ jsxRuntimeExports.jsxs( 46 "button", 47 { 48 onClick: () => setIsCreating(true), 49 className: "flex items-center gap-2 px-4 py-2 bg-zinc-900 dark:bg-white text-white dark:text-black rounded-lg font-bold hover:opacity-90 transition-opacity", 50 children: [ 51 /* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { size: 18 }), 52 " ", 53 t("playlists.new", "New Playlist") 54 ] 55 } 56 ) 57 ] }), 58 isCreating && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-8 p-4 bg-zinc-100 dark:bg-zinc-800 rounded-xl flex flex-col gap-3 animate-in fade-in slide-in-from-top-2", children: [ 59 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-3", children: [ 60 /* @__PURE__ */ jsxRuntimeExports.jsx( 61 "input", 62 { 63 value: newTitle, 64 onChange: (e) => setNewTitle(e.target.value), 65 placeholder: t("playlists.placeholder", "Enter playlist name..."), 66 className: "flex-1 bg-white dark:bg-black border border-zinc-200 dark:border-zinc-700 rounded-lg px-4 py-2 outline-none focus:ring-2 focus:ring-indigo-500 text-zinc-900 dark:text-white", 67 autoFocus: true, 68 onKeyDown: (e) => e.key === "Enter" && handleCreate() 69 } 70 ),
71 /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: handleCreate, disabled: !newTitle.trim(), className: "px-4 py-2 bg-indigo-600 text-white rounded-lg font-bold disabled:opacity-50", children: t("playlists.create", "Create") }), 72 /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setIsCreating(false), className: "px-4 py-2 bg-zinc-200 dark:bg-zinc-700 text-zinc-700 dark:text-zinc-300 rounded-lg font-bold", children: t("common.cancel", "Cancel") }) 73 ] }), 74 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-2 text-sm text-zinc-600 dark:text-zinc-400 cursor-pointer w-fit", children: [ 75 /* @__PURE__ */ jsxRuntimeExports.jsx( 76 "input", 77 { 78 type: "checkbox", 79 checked: isPublic, 80 onChange: (e) => setIsPublic(e.target.checked), 81 className: "rounded border-zinc-300 text-indigo-600 focus:ring-indigo-500" 82 } 83 ), 84 t("playlists.makePublic", "Make this playlist public") 85 ] }) 86 ] }),
87 loading ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-center py-20 text-zinc-500", children: t("common.loading", "Loading...") }) : playlists.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-center py-20 bg-zinc-50 dark:bg-zinc-900/50 rounded-xl border border-dashed border-zinc-200 dark:border-zinc-800", children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-zinc-500", children: t("playlists.noPlaylists", "No playlists found.") }) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6", children: playlists.map((pl) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-xl overflow-hidden hover:border-indigo-500 transition-colors group cursor-pointer relative", children: [ 88 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "aspect-video bg-zinc-200 dark:bg-zinc-800 relative group-hover:opacity-90 transition-opacity", children: [ 89 pl.thumbnail ? /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: pl.thumbnail, className: "w-full h-full object-cover" }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-full h-full flex items-center justify-center text-zinc-400", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ListMusic, { size: 48, opacity: 0.2 }) }),
90 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute inset-0 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-12 h-12 bg-indigo-600 rounded-full flex items-center justify-center text-white shadow-lg transform scale-90 group-hover:scale-100 transition-transform", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Play, { size: 20, fill: "currentColor", className: "ml-1" }) }) }), 91 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "absolute bottom-2 right-2 bg-black/80 text-white text-xs font-bold px-2 py-1 rounded", children: [ 92 pl.trackIds.length, 93 " tracks" 94 ] }) 95 ] }), 96 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4", children: [ 97 /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "font-bold text-zinc-900 dark:text-white truncate pr-6 flex items-center gap-2", children: [ 98 pl.title, 99 pl.isPublic && /* @__P
99URE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] bg-indigo-100 text-indigo-700 dark:bg-indigo-900/30 dark:text-indigo-400 px-1.5 py-0.5 rounded-full uppercase tracking-wider font-bold", children: "Public" }) 100 ] }), 101 /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-zinc-500 mt-1", children: [ 102 "Updated ", 103 new Date(pl.createdAt).toLocaleDateString() 104 ] }), 105 /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "absolute bottom-4 right-4 p-1.5 hover:bg-zinc-100 dark:hover:bg-zinc-800 rounded-full text-zinc-500 hover:text-black dark:hover:text-white transition-colors", children: /* @__PURE__ */ jsxRuntimeExports.jsx(EllipsisVertical, { size: 16 }) }) 106 ] }) 107 ] }, pl.id)) }) 108 ] }); 109}; 110export { 111 PlaylistsPage as default 112};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.