1import { r as reactExports, j as jsxRuntimeExports } from "./vendor-react-Bay9Y7Lb.js"; 2import { a as api } from "./index-D0Bmh-UX.js"; 3import { A as AdSlot } from "./AdSlot-CPW4Sb2o.js"; 4import { u as useTranslation } from "./vendor-i18n-R-bMoYp_.js"; 5import { d4 as ShieldCheck, cm as ArrowRight, bf as Search, b6 as LoaderCircle, bg as Music, bI as Star, ck as HardDrive, bU as Play, c$ as Download, bb as User, dM as Calendar } from "./vendor-dVNaLJx_.js"; 6const SoundfontsPage = ({ onNavigate, isAdmin }) => { 7 const { t } = useTranslation(); 8 const [soundfonts, setSoundfonts] = reactExports.useState([]); 9 const [loading, setLoading] = reactExports.useState(true); 10 const [total, setTotal] = reactExports.useState(0); 11 const [search, setSearch] = reactExports.useState(""); 12 const [sort, setSort] = reactExports.useState("newest"); 13 const [page, setPage] = reactExports.useState(1); 14 const limit = 20; 15 reactExports.useEffect(() => { 16 fetchSoundfonts(); 17 }, [page, sort, search]); 18 const fetchSoundfonts = async () => { 19 setLoading(true); 20 try { 21 const res = await api.getPublicSoundfonts({ page, limit, sort, search }); 22 setSoundfonts(res.soundfonts); 23 setTotal(res.total); 24 } catch (error) { 25 console.error("Failed to load soundfonts:", error); 26 } finally { 27 setLoading(false); 28 } 29 }; 30 const handleSearchSubmit = (e) => { 31 e.preventDefault(); 32 setPage(1); 33 fetchSoundfonts(); 34 }; 35 const formatSize = (bytes) => { 36 const mb = bytes / (1024 * 1024); 37 return mb >= 1024 ? (mb / 1024).toFixed(2) + " GB" : mb.toFixed(1) + " MB"; 38 }; 39 if (!isAdmin) { 40 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "max-w-4xl mx-auto py-24 px-6 text-center", children: [
41 /* @__PURE__ */ jsxRuntimeExports.jsx(ShieldCheck, { className: "w-24 h-24 mx-auto text-zinc-300 dark:text-zinc-700 mb-6" }), 42 /* @__PURE__ */ jsxRuntimeExports.jsx("h1", { className: "text-3xl font-black text-zinc-900 dark:text-white mb-4", children: "Coming Soon" }), 43 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-lg text-zinc-600 dark:text-zinc-400", children: "The Community Soundfonts gallery is currently in beta testing. Check back later!" }) 44 ] }); 45 } 46 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "max-w-7xl mx-auto px-4 py-8 sm:px-6 lg:px-8", children: [ 47 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative overflow-hidden rounded-3xl bg-gradient-to-br from-indigo-600 via-purple-600 to-indigo-800 p-8 sm:p-12 text-white shadow-2xl mb-12", children: [ 48 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute top-0 right-0 -mt-16 -mr-16 w-64 h-64 bg-white opacity-10 rounded-full blur-3xl mix-blend-overlay" }), 49 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute bottom-0 left-0 w-full h-1/2 bg-gradient-to-t from-black/20 to-transparent" }),
50 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative z-10 flex flex-col md:flex-row items-center justify-between gap-8", children: [ 51 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "max-w-2xl", children: [ 52 /* @__PURE__ */ jsxRuntimeExports.jsx("h1", { className: "text-4xl sm:text-5xl font-black tracking-tight mb-4 text-transparent bg-clip-text bg-gradient-to-r from-white to-indigo-100", children: "Community Soundfonts" }), 53 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-lg sm:text-xl text-indigo-100/90 leading-relaxed max-w-xl", children: "Discover, play, and download high-quality soundfonts shared by the community. Extracted, optimized, and ready for your next masterpiece." }) 54 ] }), 55 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "shrink-0 flex flex-col gap-3 w-full md:w-auto", children: [ 56 /* @__PURE__ */ jsxRuntimeExports.jsxs( 57 "button", 58 { 59 onClick: () => onNavigate("/soundfonts/upload"), 60 className: "flex items-center justify-center gap-2 px-8 py-4 bg-white text-indigo-700 hover:bg-indigo-50 font-bold rounded-2xl transition-all shadow-lg hover:shadow-xl hover:-translate-y-1 active:scale-95 group", 61 children: [
62 /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowRight, { className: "w-5 h-5 group-hover:translate-x-1 transition-transform" }), 63 "Upload Soundfont" 64 ] 65 } 66 ), 67 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-center text-sm text-indigo-200 font-medium bg-black/10 px-4 py-2 rounded-xl backdrop-blur-sm border border-white/5", children: "Admin Beta Access" }) 68 ] }) 69 ] }) 70 ] }), 71 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mb-8", children: /* @__PURE__ */ jsxRuntimeExports.jsx(AdSlot, { placement: "explore-top", className: "mb-8" }) }), 72 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col md:flex-row justify-between items-center gap-4 mb-8", children: [ 73 /* @__PURE__ */ jsxRuntimeExports.jsxs("form", { onSubmit: handleSearchSubmit, className: "relative w-full md:max-w-md", children: [ 74 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute inset-y-0 left-0 pl-4 flex items-center pointer-events-none", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Search, { className: "h-5 w-5 text-zinc-400" }) }),
75 /* @__PURE__ */ jsxRuntimeExports.jsx( 76 "input", 77 { 78 type: "text", 79 className: "block w-full pl-11 pr-4 py-3 bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-2xl leading-5 bg-transparent placeholder-zinc-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm transition-all shadow-sm focus:shadow-md text-zinc-900 dark:text-zinc-100", 80 placeholder: "Search soundfonts by name or genre...", 81 value: search, 82 onChange: (e) => setSearch(e.target.value) 83 } 84 ) 85 ] }), 86 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-2 w-full md:w-auto bg-white dark:bg-zinc-900 p-1.5 rounded-2xl border border-zinc-200 dark:border-zinc-800 shadow-sm", children: ["newest", "popular", "rated"].map((s) => /* @__PURE__ */ jsxRuntimeExports.jsx( 87 "button", 88 { 89 onClick: () => setSort(s), 90 className: `flex-1 md:flex-none px-6 py-2 rounded-xl text-sm font-semibold transition-all ${sort === s ? "bg-indigo-100 dark:bg-indigo-900/30 text-indigo-700 dark:text-indigo-300 shadow-sm" : "text-zinc-600 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-zinc-800 hover:text-zinc-900 dark:hover:text-zinc-100"}`, 91 children: s.charAt(0).toUpperCase() + s.slice(1) 92 }, 93 s 94 )) }) 95 ] }),
96 loading ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-center py-20", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-center py-20", children: /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "w-8 h-8 animate-spin text-indigo-500" }) }) }) : soundfonts.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center py-20 bg-zinc-50 dark:bg-zinc-900/50 rounded-3xl border border-zinc-200 dark:border-zinc-800 border-dashed", children: [ 97 /* @__PURE__ */ jsxRuntimeExports.jsx(Music, { className: "mx-auto h-16 w-16 text-zinc-300 dark:text-zinc-700 mb-4" }), 98 /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "mt-2 text-xl font-bold text-zinc-900 dark:text-white", children: "No soundfonts found" }), 99 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "mt-2 text-zinc-500 dark:text-zinc-400", children: "Try adjusting your search terms." }) 100 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6", children: soundfonts.map((sf) => { 101 var _a, _b; 102 return /* @__PURE__ */ jsxRuntimeExports.jsxs( 103 "div", 104 { 105 onClick: () => onNavigate(`/soundfont/${sf.slug}`), 106 className: "group bg-white dark:bg-zinc-900 rounded-3xl border border-zinc-200 dark:border-zinc-800 overflow-hidden hover:shadow-2xl hover:shadow-indigo-500/10 hover:-translate-y-1 transition-all cursor-pointer flex flex-col h-full", 107 children: [
108 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-6 flex-1 flex flex-col", children: [ 109 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-start mb-4", children: [ 110 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "bg-indigo-50 dark:bg-indigo-900/30 text-indigo-600 dark:text-indigo-400 p-3 rounded-2xl group-hover:scale-110 group-hover:rotate-3 transition-transform duration-300", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Music, { className: "w-6 h-6" }) }), 111 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 bg-yellow-50 dark:bg-yellow-900/20 text-yellow-700 dark:text-yellow-500 px-3 py-1 rounded-full text-sm font-bold shadow-sm", children: [ 112 /* @__PURE__ */ jsxRuntimeExports.jsx(Star, { className: "w-4 h-4 fill-current" }), 113 sf.averageRating.toFixed(1) 114 ] }) 115 ] }), 116 /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-xl font-black text-zinc-900 dark:text-white mb-2 line-clamp-1 group-hover:text-indigo-600 dark:group-hover:text-indigo-400 transition-colors", children: sf.name }),
117 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-zinc-500 dark:text-zinc-400 text-sm line-clamp-2 mb-4 flex-1 leading-relaxed", children: sf.description || "No description provided." }), 118 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between text-xs font-semibold text-zinc-500 dark:text-zinc-400 bg-zinc-50 dark:bg-zinc-800/50 p-3 rounded-xl border border-zinc-100 dark:border-zinc-800", children: [ 119 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5", title: "File Size", children: [ 120 /* @__PURE__ */ jsxRuntimeExports.jsx(HardDrive, { className: "w-4 h-4" }), 121 formatSize(sf.fileSize) 122 ] }), 123 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5", title: "Presets", children: [ 124 /* @__PURE__ */ jsxRuntimeExports.jsx(Play, { className: "w-4 h-4" }), 125 sf.presetCount, 126 " Presets" 127 ] }),
128 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5", title: "Downloads", children: [ 129 /* @__PURE__ */ jsxRuntimeExports.jsx(Download, { className: "w-4 h-4" }), 130 sf.downloads 131 ] }) 132 ] }) 133 ] }), 134 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-6 py-4 border-t border-zinc-100 dark:border-zinc-800 bg-zinc-50/50 dark:bg-zinc-900/50 flex items-center justify-between", children: [ 135 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 text-sm text-zinc-600 dark:text-zinc-400 font-medium", children: [ 136 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-6 h-6 rounded-full bg-zinc-200 dark:bg-zinc-700 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntimeExports.jsx(User, { className: "w-3.5 h-3.5" }) }), 137 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate max-w-[120px]", children: ((_a = sf.user) == null ? void 0 : _a.displayName) || ((_b = sf.user) == null ? void 0 : _b.username) || "Community" }) 138 ] }),
139 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-zinc-400 dark:text-zinc-500 flex items-center gap-1", children: [ 140 /* @__PURE__ */ jsxRuntimeExports.jsx(Calendar, { className: "w-3 h-3" }), 141 new Date(sf.createdAt).toLocaleDateString() 142 ] }) 143 ] }) 144 ] 145 }, 146 sf.id 147 ); 148 }) }), 149 total > limit && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-12 flex justify-center gap-2", children: Array.from({ length: Math.ceil(total / limit) }).map((_, i) => /* @__PURE__ */ jsxRuntimeExports.jsx( 150 "button", 151 { 152 onClick: () => setPage(i + 1), 153 className: `w-10 h-10 rounded-xl font-bold transition-all ${page === i + 1 ? "bg-indigo-600 text-white shadow-md shadow-indigo-500/20" : "bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 text-zinc-600 dark:text-zinc-400 hover:bg-zinc-50 dark:hover:bg-zinc-800 hover:border-zinc-300"}`, 154 children: i + 1 155 }, 156 i 157 )) }) 158 ] }); 159}; 160export { 161 SoundfontsPage 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.