PageSourceSearch

https://www.hamienet.com/assets/PlaylistsPage-Br-5J847.js

js hamienet.com collected 2026-09-24 18:59:20 UTC 8,380 bytes, 112 lines download raw bytes

1import { r as reactExports, j as jsxRuntimeExports } from "./vendor-react-Bay9Y7Lb.js";
2import { a as api } from "./index-D0Bmh-UX.js";
3import { u as useTranslation } from "./vendor-i18n-R-bMoYp_.js";
4import { bB as ListMusic, ce as Plus, bU as Play, b_ as EllipsisVertical } from "./vendor-dVNaLJx_.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.