PageSourceSearch

https://www.hamienet.com/assets/CollectionIndexPage-B76qFKH2.js

js hamienet.com collected 2026-09-24 18:59:29 UTC 12,194 bytes, 162 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 { g as getColorsFromHash, m as getOptimizedImageUrl } from "./utils-BYCVoSTN.js";
4import { g as getBilingualTitle, p as parseMultilingualData } from "./bilingual-B8ftIVs5.js";
5import { u as useTranslation } from "./vendor-i18n-R-bMoYp_.js";
6import { cj as Layers, cL as RefreshCw, bi as Sparkles, bN as Library, dM as Calendar, cm as ArrowRight } from "./vendor-dVNaLJx_.js";
7const CollectionIndexPage = ({ onNavigate }) => {
8  const { t, i18n } = useTranslation();
9  const [collections, setCollections] = reactExports.useState([]);
10  const [isLoading, setIsLoading] = reactExports.useState(true);
11  const [error, setError] = reactExports.useState(null);
12  const [imageErrors, setImageErrors] = reactExports.useState({});
13  reactExports.useEffect(() => {
14    document.title = t("collections.pageTitle", "Browse Curated MIDI Collections | HamieNET");
15    const metaDesc = document.querySelector('meta[name="description"]');
16    if (metaDesc) {
17      metaDesc.setAttribute("content", "Explore hand-crafted collections of MIDI files organized by theme, composer, style, and musical eras. Discover lists like Broadway Musicals, Classical Masters, and more.");
18    }
19    const fetchCollections = async () => {
20      try {
21        setIsLoading(true);
22        const data = await api.getCollections();
23        setCollections(data);
24        setError(null);
25      } catch (err) {
26        console.error("[CollectionIndexPage Load Error]", err);
27        const errMsg = err instanceof Error ? err.message : "Failed to load collections. Please try again later.";
28        setError(errMsg);
29      } finally {
30        setIsLoading(false);
31      }
32    };
33    fetchCollections();
34  }, [t]);
35  if (isLoading) {
36    return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center justify-center min-h-[60vh] bg-zinc-50 dark:bg-[#0a0a0a]", children: [
37      /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-12 h-12 border-4 border-indigo-500 border-t-transparent rounded-full animate-spin mb-4" }),
38      /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-zinc-500 dark:text-zinc-400 text-sm font-semibold animate-pulse", children: t("collections.loading", "Loading themed collections...") })
39    ] });
40  }
41  if (error) {
42    return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "max-w-md mx-auto my-20 p-8 rounded-2xl bg-red-50 dark:bg-red-950/20 border border-red-200 dark:border-red-900/30 text-center animate-in fade-in", children: [
43      /* @__PURE__ */ jsxRuntimeExports.jsx(Layers, { className: "mx-auto text-red-500 dark:text-red-400 mb-4", size: 40 }),
44      /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-lg font-bold text-red-800 dark:text-red-300 mb-2", children: t("collections.errorTitle", "Error Loading Collections") }),
45      /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-red-600 dark:text-red-400 mb-6", children: error }),
46      /* @__PURE__ */ jsxRuntimeExports.jsxs(
47        "button",
48        {
49          onClick: () => window.location.reload(),
50          className: "inline-flex items-center gap-2 bg-red-600 hover:bg-red-700 text-white font-bold text-sm px-6 py-2.5 rounded-xl transition shadow-lg shadow-red-600/20",
51          children: [
52            /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { size: 14 }),
53            t("collections.retry", "Retry")
54          ]
55        }
56      )
57    ] });
58  }
59  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-6 md:p-10 max-w-[2000px] mx-auto animate-in fade-in duration-700 bg-zinc-50 dark:bg-[#0a0a0a] min-h-full", children: [
60    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "max-w-4xl mb-12", children: [
61      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "inline-flex items-center gap-2 text-indigo-500 font-black text-xs uppercase tracking-widest mb-3 bg-indigo-50 dark:bg-indigo-950/30 px-3 py-1 rounded-full border border-indigo-100 dark:border-indigo-900/40", children: [
62        /* @__PURE__ */ jsxRuntimeExports.jsx(Sparkles, { size: 14 }),
63        t("collections.curatedSoundscapes", "Curated Soundscapes")
64      ] }),
65      /* @__PURE__ */ jsxRuntimeExports.jsx("h1", { className: "text-4xl md:text-5xl font-black tracking-tight text-zinc-900 dark:text-white mb-4", children: t("collections.browseCollections", "Browse Collections") }),
66      /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-zinc-600 dark:text-zinc-400 text-base md:text-lg font-medium leading-relaxed", children: t("collections.browseDescription", "Discover hand-crafted selections of MIDI tracks grouped by themes, stage shows, composers, and styles. Each collection is carefully arranged to guide you through different musical journeys.") })
67    ] }),
68    collections.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-12 text-center rounded-3xl border-2 border-dashed border-zinc-200 dark:border-zinc-800 bg-white dark:bg-zinc-900/30 max-w-xl mx-auto my-12", children: [
69      /* @__PURE__ */ jsxRuntimeExports.jsx(Library, { className: "mx-auto text-zinc-400 dark:text-zinc-600 mb-4", size: 48 }),
70      /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-lg font-bold text-zinc-700 dark:text-zinc-300 mb-1", children: t("collections.noCollections", "No Collections Published") }),
71      /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-zinc-500 dark:text-zinc-400", children: t("collections.noCollectionsDesc", "Check back later! We are working on curating some amazing MIDI playlists and thematic pages for you.") })
72    ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-8", children: collections.map((collection, idx) => {
73      const colors = getColorsFromHash(collection.title + collection.slug);
74      const formattedDate = collection.createdAt ? new Date(collection.createdAt).toLocaleDateString(void 0, {
75        year: "numeric",
76        month: "short"
77      }) : null;
78      const bilingual = getBilingualTitle(collection.title, collection.subtitle, i18n.language);
79      const descDict = parseMultilingualData(collection.description);
80      const lang = (i18n.language || "en").toLowerCase();
81      const langPrefix = lang.split("-")[0];
82      const localizedDescription = descDict && (descDict[lang] || descDict[langPrefix] || descDict.en || Object.values(descDict)[0]) || (typeof collection.description === "string" && !collection.description.trim().startsWith("{") && !collection.description.trim().startsWith("[") ? collection.description : null);
83      return /* @__PURE__ */ jsxRuntimeExports.jsxs(
84        "a",
85        {
86          href: `/collections/${collection.slug}`,
87          onClick: (e) => {
88            if (!e.ctrlKey && !e.metaKey && !e.shiftKey && e.button === 0) {
89              e.preventDefault();
90              onNavigate("collection", collection.slug);
91            }
92          },
93          className: "group relative rounded-3xl overflow-hidden bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800/80 shadow-md hover:shadow-2xl hover:shadow-indigo-500/10 transition-all duration-500 hover:-translate-y-2 cursor-pointer flex flex-col h-[400px] animate-in fade-in slide-in-from-bottom-8 no-underline text-inherit",
94          style: { animationDelay: `${idx * 80}ms` },
95          title: bilingual.hoverTooltip,
96          children: [
97            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative h-48 w-full overflow-hidden shrink-0 select-none", children: [
98              collection.heroImage && !imageErrors[collection.id] ? /* @__PURE__ */ jsxRuntimeExports.jsx(
99                "img",
100                {
101                  src: getOptimizedImageUrl(collection.heroImage, "card"),
102                  alt: bilingual.altText,
103                  title: bilingual.hoverTooltip,
104                  className: "w-full h-full object-cover transition-transform duration-700 group-hover:scale-110",
105                  loading: "lazy",
106                  onError: () => setImageErrors((prev) => ({ ...prev, [collection.id]: true }))
107                }
108              ) : /* @__PURE__ */ jsxRuntimeExports.jsx(
109                "div",
110                {
111                  className: "w-full h-full transition-transform duration-700 group-hover:scale-110",
112                  style: { background: colors.gradient },
113                  title: bilingual.hoverTooltip
114                }
115              ),
116              /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute inset-0 bg-gradient-to-t from-black/80 via-black/30 to-transparent" }),
117              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "absolute top-4 right-4 flex items-center gap-1.5", children: [
118                bilingual.nativeBadge && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "bg-emerald-600/90 text-white font-black text-[10px] tracking-wider px-2 py-1 rounded-lg backdrop-blur-sm shadow border border-emerald-400/30", children: bilingual.nativeBadge }),
119                /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "bg-indigo-600/90 text-white font-black text-[10px] uppercase tracking-wider px-3 py-1 rounded-xl backdrop-blur-sm shadow-lg border border-indigo-400/20", children: collection.sectionCount === 1 ? t("collections.sectionCount_one", "1 Section", { count: 1 }) : t("collections.sectionCount_other", "{{count}} Sections", { count: collection.sectionCount || 0 }) })
120              ] })
121            ] }),
122            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-6 flex-1 flex flex-col justify-between", children: [
123              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
124                /* @__PURE__ */ jsxRuntimeExports.jsx(
125                  "h2",
126                  {
127                    className: "text-xl font-extrabold text-zinc-900 dark:text-white line-clamp-2 group-hover:text-indigo-500 transition-colors leading-tight",
128                    title: bilingual.hoverTooltip,
129                    children: bilingual.mainTitle
130                  }
131                ),
132                bilingual.subTitle && /* @__PURE__ */ jsxRuntimeExports.jsx(
133                  "p",
134                  {
135                    className: "text-zinc-500 dark:text-zinc-400 text-xs font-semibold uppercase tracking-wider line-clamp-1",
136                    title: bilingual.hoverTooltip,
137                    children: bilingual.subTitle
138                  }
139                ),
140                localizedDescription && /* @__P
140URE__ */ jsxRuntimeExports.jsx("p", { className: "text-zinc-500 dark:text-zinc-400 text-sm line-clamp-2 leading-relaxed pt-1", children: localizedDescription })
141              ] }),
142              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between pt-4 border-t border-zinc-100 dark:border-zinc-800/80 mt-4 shrink-0", children: [
143                /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-1 text-[11px] text-zinc-400 dark:text-zinc-500 font-bold uppercase", children: formattedDate && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
144                  /* @__PURE__ */ jsxRuntimeExports.jsx(Calendar, { size: 12 }),
145                  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: formattedDate })
146                ] }) }),
147                /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-[11px] font-black uppercase tracking-widest text-indigo-500 group-hover:text-indigo-400 transition-colors", children: [
148                  t("collections.explore", "Explore"),
149                  /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowRight, { size: 12, className: "transform transition-transform duration-300 group-hover:translate-x-1" })
150                ] })
151              ] })
152            ] })
153          ]
154        },
155        collection.id
156      );
157    }) })
158  ] });
159};
160export {
161  CollectionIndexPage as default
162};

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.