PageSourceSearch

https://www.hamienet.com/assets/NewlyUploadedPage-CswaPEfP.js

js hamienet.com collected 2026-09-24 18:59:27 UTC 7,964 bytes, 165 lines download raw bytes

1import { r as reactExports, j as jsxRuntimeExports, R as React } from "./vendor-react-Bay9Y7Lb.js";
2import { V as VideoCard } from "./main-CznOH3wZ.js";
3import { u as useShouldShowAd, A as AdSlot } from "./AdSlot-CPW4Sb2o.js";
4import { a as api } from "./index-D0Bmh-UX.js";
5import { u as useTranslation } from "./vendor-i18n-R-bMoYp_.js";
6import { bL as Clock, cv as LayoutGrid, cw as List } from "./vendor-dVNaLJx_.js";
7import "./vendor-react-three-MDLA5jog.js";
8import "./utils-BYCVoSTN.js";
9import "./synth-BE1TSTD4.js";
10import "./wasm-synth-adapter-BrqgBX1y.js";
11import "./vendor-spessasynth-DH8n6o_V.js";
12import "./vendor-audio-DH3w0BzW.js";
13import "./Waveform-MxtdejK7.js";
14import "./vendor-framer-C8eEgkdL.js";
15import "./labTools-BATZiaPB.js";
16import "./UserAvatar-BQN4jlY-.js";
17const NewlyUploadedPage = ({
18  onSelectTrack,
19  onToggleWatchLater,
20  watchLaterSet,
21  onAddToQueue,
22  onAddToPlaylist
23}) => {
24  const { t } = useTranslation();
25  const shouldShowAd = useShouldShowAd("exploreList");
26  const [tracks, setTracks] = reactExports.useState([]);
27  const [loading, setLoading] = reactExports.useState(true);
28  const [loadingMore, setLoadingMore] = reactExports.useState(false);
29  const [hasMore, setHasMore] = reactExports.useState(true);
30  const [viewMode, setViewMode] = reactExports.useState(() => {
31    return localStorage.getItem("hamie_view_mode") || "list";
32  });
33  const observerRef = reactExports.useRef(null);
34  const sentinelRef = reactExports.useRef(null);
35  reactExports.useEffect(() => {
36    localStorage.setItem("hamie_view_mode", viewMode);
37  }, [viewMode]);
38  reactExports.useEffect(() => {
39    const fetchInitial = async () => {
40      setLoading(true);
41      try {
42        const data = await api.getTracks("", "all", "recent", 30, 0);
43        setTracks(data);
44        if (data.length < 30 || data.length >= 300) {
45          setHasMore(false);
46        }
47      } catch (e) {
48        console.error("Failed to load initial newly uploaded tracks", e);
49      } finally {
50        setLoading(false);
51      }
52    };
53    fetchInitial();
54  }, []);
55  const loadMore = async () => {
56    if (loading || loadingMore || !hasMore || tracks.length >= 300) return;
57    setLoadingMore(true);
58    try {
59      const skip = tracks.length;
60      const limit = Math.min(30, 300 - skip);
61      const data = await api.getTracks("", "all", "recent", limit, skip);
62      if (data.length === 0) {
63        setHasMore(false);
64      } else {
65        setTracks((prev) => {
66          const nextTracks = [...prev, ...data];
67          if (nextTracks.length >= 300) {
68            setHasMore(false);
69          }
70          return nextTracks;
71        });
72      }
73    } catch (e) {
74      console.error("Failed to load more newly uploaded tracks", e);
75    } finally {
76      setLoadingMore(false);
77    }
78  };
79  reactExports.useEffect(() => {
80    if (loading) return;
81    if (observerRef.current) {
82      observerRef.current.disconnect();
83    }
84    observerRef.current = new IntersectionObserver(
85      (entries) => {
86        if (entries[0].isIntersecting && hasMore && !loadingMore && tracks.length < 300) {
87          loadMore();
88        }
89      },
90      { threshold: 0.1, rootMargin: "100px" }
91    );
92    if (sentinelRef.current) {
93      observerRef.current.observe(sentinelRef.current);
94    }
95    return () => {
96      if (observerRef.current) {
97        observerRef.current.disconnect();
98      }
99    };
100  }, [loading, loadingMore, hasMore, tracks.length]);
101  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-6 max-w-6xl mx-auto animate-in fade-in duration-300", children: [
102    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between gap-4 mb-8 border-b border-zinc-200 dark:border-zinc-800 pb-4", children: [
103      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-4", children: [
104        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-12 h-12 sm:w-16 sm:h-16 bg-indigo-500/10 dark:bg-indigo-500/20 text-indigo-600 dark:text-indigo-400 rounded-full flex items-center justify-center", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { size: 28 }) }),
105        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
106          /* @__PURE__ */ jsxRuntimeExports.jsx("h1", { className: "text-2xl sm:text-3xl font-bold text-zinc-900 dark:text-white", children: t("home.newlyUploaded", "Newly Uploaded Playlist") }),
107          /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-zinc-500 dark:text-zinc-400 mt-1", children: [
108            t("home.newlyUploadedDescription", "Latest MIDI preservation files added to the archive"),
109            " (Limit 300)"
110          ] })
111        ] })
112      ] }),
113      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center bg-zinc-100 dark:bg-zinc-800 p-1 rounded-xl shadow-inner", children: [
114        /* @__PURE__ */ jsxRuntimeExports.jsx(
115          "button",
116          {
117            onClick: () => setViewMode("grid"),
118            className: `p-1.5 rounded-lg transition-all ${viewMode === "grid" ? "bg-white dark:bg-zinc-700 text-indigo-600 shadow-sm" : "text-zinc-400 hover:text-zinc-600 dark:hover:text-zinc-300"}`,
119            title: "Grid View",
120            children: /* @__PURE__ */ jsxRuntimeExports.jsx(LayoutGrid, { size: 18 })
121          }
122        ),
123        /* @__PURE__ */ jsxRuntimeExports.jsx(
124          "button",
125          {
126            onClick: () => setViewMode("list"),
127            className: `p-1.5 rounded-lg transition-all ${viewMode === "list" ? "bg-white dark:bg-zinc-700 text-indigo-600 shadow-sm" : "text-zinc-400 hover:text-zinc-600 dark:hover:text-zinc-300"}`,
128            title: "List View",
129            children: /* @__PURE__ */ jsxRuntimeExports.jsx(List, { size: 18 })
130          }
131        )
132      ] })
133    ] }),
134    tracks.length > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: viewMode === "grid" ? "grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-6 gap-x-4 gap-y-8" : "flex flex-col gap-3", children: tracks.map((track, idx) => {
135      const showAd = (idx + 1) % 12 === 0;
136      return /* @__PURE__ */ jsxRuntimeExports.jsxs(React.Fragment, { children: [
137        /* @__PURE__ */ jsxRuntimeExports.jsx(
138          VideoCard,
139          {
140            track,
141            onSelect: (t2) => onSelectTrack(t2, void 0, tracks),
142            onToggleWatchLater,
143            isWatchLater: watchLaterSet.has(track.id),
144            variant: viewMode,
145            onAddToQueue,
146            onAddToPlaylist,
147            playlist: tracks
148          }
149        ),
150        showAd && shouldShowAd && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: viewMode === "grid" ? "col-span-1" : "w-full", children: /* @__PURE__ */ jsxRuntimeExports.jsx(AdSlot, { type: "exploreList", className: "!my-0 h-full min-h-[200px]" }) })
151      ] }, track.id);
152    }) }) : !loading ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-center py-20", children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-zinc-400", children: t("list.empty", "This list is empty.") }) }) : null,
153    loading && tracks.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: viewMode === "grid" ? "grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-6 gap-x-4 gap-y-8" : "flex flex-col gap-3", children: Array.from({ length: 12 }).map((_, idx) => /* @__PURE__ */ jsxRuntimeExports.jsx(
154      "div",
155      {
156        className: `animate-pulse bg-zinc-100 dark:bg-zinc-800 rounded-2xl ${viewMode === "grid" ? "h-48 w-full" : "h-16 w-full"}`
157      },
158      `skeleton-${idx}`
159    )) }),
160    hasMore && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref: sentinelRef, className: "py-8 flex justify-center items-center", children: loadingMore && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "animate-spin rounded-full h-8 w-8 border-b-2 border-indigo-600" }) })
161  ] });
162};
163export {
164  NewlyUploadedPage as default
165};

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.