1import { r as reactExports, j as jsxRuntimeExports } from "./vendor-react-Bay9Y7Lb.js"; 2import { n as getOptimizedImageUrl } from "./utils-CEVb7nN1.js"; 3import { g as getBilingualTitle } from "./bilingual-CBk-npe4.js"; 4import { a as useAdmin } from "./main-aQ5jZgYp.js"; 5import { u as useTranslation } from "./vendor-i18n-BC7ZMXWQ.js"; 6import { ck as Layers, c_ as ChevronLeft, bF as ChevronRight } from "./vendor-D0P4XgNj.js"; 7import { S as SectionContent } from "./SectionContent-dHWQOZ9q.js"; 8const NetflixSectionCard = ({ section, onClick, trackCount, className, aspectRatio = "4/5" }) => { 9 const [imageError, setImageError] = reactExports.useState(false); 10 const { i18n } = useTranslation(); 11 const { staffModeEnabled } = useAdmin(); 12 const { mainTitle: rawMainTitle, subTitle, hoverTooltip, altText, nativeBadge, nativeTitle } = getBilingualTitle(section.title, section.subtitle, i18n.language); 13 const mainTitle = rawMainTitle.replace(/^\d+\.\s*/, ""); 14 const resolvedTrackCount = trackCount !== void 0 ? trackCount : section.trackCount; 15 const aspectClass = aspectRatio === "16/9" || aspectRatio === "video" ? "aspect-[16/9]" : "aspect-[4/5]"; 16 return /* @__PURE__ */ jsxRuntimeExports.jsxs( 17 "div", 18 { 19 onClick: (e) => { 20 e.preventDefault(); 21 e.stopPropagation(); 22 onClick(); 23 }, 24 className: `group relative flex flex-col w-full cursor-pointer shrink-0 transition-transform duration-300 hover:scale-105 hover:z-10 ${className || "min-w-[160px] md:min-w-[200px] max-w-[240px]"}`, 25 children: [
26 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `relative w-full ${aspectClass} rounded-xl overflow-hidden bg-zinc-100 dark:bg-zinc-800 shadow-sm group-hover:shadow-xl transition-shadow duration-300 border border-zinc-200/50 dark:border-zinc-700/50`, children: [ 27 section.bannerImage && !imageError ? /* @__PURE__ */ jsxRuntimeExports.jsx( 28 "img", 29 { 30 src: getOptimizedImageUrl(section.bannerImage, "card"), 31 className: "w-full h-full object-cover transition-transform duration-500 group-hover:scale-110", 32 alt: altText || mainTitle, 33 title: hoverTooltip || mainTitle, 34 loading: "lazy", 35 onError: () => setImageError(true) 36 } 37 ) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full h-full bg-gradient-to-br from-indigo-500/20 to-purple-500/20 flex flex-col items-center justify-center p-4 text-center", children: [ 38 /* @__PURE__ */ jsxRuntimeExports.jsx(Layers, { className: "text-indigo-500/50 mb-2", size: 32 }),
39 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-bold text-indigo-700/50 dark:text-indigo-300/50 line-clamp-2", children: mainTitle }) 40 ] }), 41 nativeBadge && /* @__PURE__ */ jsxRuntimeExports.jsx( 42 "div", 43 { 44 className: "absolute top-2 left-2 bg-black/60 backdrop-blur-md text-white/90 text-[9px] font-black tracking-widest px-1.5 py-0.5 rounded shadow-sm border border-white/10 uppercase select-none", 45 title: `Native Script: ${nativeBadge}`, 46 children: nativeBadge 47 } 48 ), 49 staffModeEnabled && resolvedTrackCount === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute top-2 right-2 bg-amber-500/90 text-zinc-950 font-black text-[10px] uppercase tracking-wider px-2 py-0.5 rounded-md backdrop-blur-md shadow-md border border-amber-400/40", children: "Unbound (0)" }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute top-2 right-2 bg-black/60 backdrop-blur-md text-white text-[10px] font-bold px-2 py-1 rounded-md min-w-[40px] text-center", children: resolvedTrackCount !== void 0 ? `${resolvedTrackCount} Tracks` : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "inline-block w-6 h-2 bg-white/40 animate-pulse rounded" }) }) 50 ] }),
51 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-2 px-1", title: hoverTooltip || mainTitle, children: [ 52 /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-sm font-bold text-zinc-900 dark:text-zinc-100 truncate group-hover:text-indigo-600 dark:group-hover:text-indigo-400 transition-colors", children: mainTitle }), 53 (subTitle || nativeTitle && nativeTitle !== mainTitle) && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] font-medium text-zinc-500 dark:text-zinc-400 truncate mt-0.5", title: hoverTooltip || subTitle || void 0, children: subTitle || nativeTitle }) 54 ] }) 55 ] 56 } 57 ); 58}; 59function CarouselRow({ children, className = "", hideArrowsOnMobile = true }) { 60 const rowRef = reactExports.useRef(null); 61 const [showLeftArrow, setShowLeftArrow] = reactExports.useState(false); 62 const [showRightArrow, setShowRightArrow] = reactExports.useState(false); 63 const [isDragging, setIsDragging] = reactExports.useState(false); 64 const [startX, setStartX] = reactExports.useState(0); 65 const [scrollLeft, setScrollLeft] = reactExports.useState(0); 66 const handleScroll = () => { 67 if (rowRef.current) { 68 const { scrollLeft: scrollLeft2, scrollWidth, clientWidth } = rowRef.current; 69 setShowLeftArrow(scrollLeft2 > 0); 70 setShowRightArrow(Math.ceil(scrollLeft2 + clientWidth) < scrollWidth); 71 } 72 }; 73 reactExports.useEffect(() => { 74 handleScroll(); 75 window.addEventListener("resize", handleScroll); 76 return () => window.removeEventListener("resize", handleScroll); 77 }, [children]); 78 reactExports.useEffect(() => { 79 const timer = setTimeout(handleScroll, 100); 80 return () => clearTimeout(timer); 81 }, []); 82 const slide = (direction) => { 83 if (rowRef.current) { 84 const { clientWidth } = rowRef.current; 85 const scrollAmount = direction === "left" ? -(clientWidth * 0.8) : clientWidth * 0.8; 86 rowRef.current.scrollBy({ left: scrollAmount, behavior: "smooth" }); 87 } 88 }; 89 const handleMouseDown = (e) => { 90 var _a, _b; 91 setIsDragging(true); 92 setStartX(e.pageX - (((_a = rowRef.current) == null ? void 0 : _a.offsetLeft) || 0)); 93 setScrollLeft(((_b = rowRef.current) == null ? void 0 : _b.scrollLeft) || 0); 94 }; 95 const handleMouseLeave = () => { 96 setIsDragging(false); 97 }; 98 const handleMouseUp = () => { 99 setIsDragging(false); 100 }; 101 const handleMouseMove = (e) => { 102 if (!isDragging || !rowRef.current) return; 103 e.preventDefault(); 104 const x = e.pageX - (rowRef.current.offsetLeft || 0); 105 const walk = (x - startX) * 2; 106 rowRef.current.scrollLeft = scrollLeft - walk; 107 }; 108 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `relative group ${className}`, children: [
109 showLeftArrow && /* @__PURE__ */ jsxRuntimeExports.jsx( 110 "button", 111 { 112 onClick: () => slide("left"), 113 className: `absolute left-0 top-0 bottom-0 z-20 w-12 bg-black/40 hover:bg-black/60 text-white flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity rounded-l-xl ${hideArrowsOnMobile ? "hidden md:flex" : "flex"}`, 114 children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronLeft, { size: 32 }) 115 } 116 ), 117 /* @__PURE__ */ jsxRuntimeExports.jsx( 118 "div", 119 { 120 ref: rowRef, 121 onScroll: handleScroll, 122 onMouseDown: handleMouseDown, 123 onMouseLeave: handleMouseLeave, 124 onMouseUp: handleMouseUp, 125 onMouseMove: handleMouseMove, 126 className: `flex items-start gap-4 overflow-x-auto scrollbar-hide pt-1 pb-1.5 ${isDragging ? "cursor-grabbing select-none" : "cursor-grab"} snap-x snap-mandatory md:snap-none`, 127 style: { scrollBehavior: isDragging ? "auto" : "smooth" }, 128 children 129 } 130 ), 131 showRightArrow && /* @__P
131URE__ */ jsxRuntimeExports.jsx( 132 "button", 133 { 134 onClick: () => slide("right"), 135 className: `absolute right-0 top-0 bottom-0 z-20 w-12 bg-black/40 hover:bg-black/60 text-white flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity rounded-r-xl ${hideArrowsOnMobile ? "hidden md:flex" : "flex"}`, 136 children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { size: 32 }) 137 } 138 ) 139 ] }); 140} 141const SectionPreviewModal = ({ 142 section, 143 activeSlug, 144 onClose, 145 currentUser, 146 onUploadRequested 147}) => { 148 const modalRef = reactExports.useRef(null); 149 reactExports.useEffect(() => { 150 const handleKeyDown = (e) => { 151 if (e.key === "Escape") onClose(); 152 }; 153 if (section) { 154 window.addEventListener("keydown", handleKeyDown); 155 } 156 return () => window.removeEventListener("keydown", handleKeyDown); 157 }, [section, onClose]); 158 reactExports.useEffect(() => { 159 if (section) { 160 document.body.style.overflow = "hidden"; 161 } else { 162 document.body.style.overflow = "auto"; 163 } 164 return () => { 165 document.body.style.overflow = "auto"; 166 }; 167 }, [section]); 168 if (!section) return null; 169 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "fixed inset-0 z-50 flex items-center justify-center p-4 sm:p-6 animate-in fade-in duration-200", children: [ 170 /* @__PURE__ */ jsxRuntimeExports.jsx( 171 "div", 172 { 173 className: "absolute inset-0 bg-black/60 backdrop-blur-sm", 174 onClick: onClose 175 } 176 ), 177 /* @__PURE__ */ jsxRuntimeExports.jsx( 178 "div", 179 { 180 ref: modalRef, 181 className: "relative w-full max-w-2xl max-h-[90vh] bg-white dark:bg-[#0f0f0f] rounded-2xl shadow-2xl overflow-hidden flex flex-col animate-in zoom-in-95 duration-200", 182 children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "overflow-y-auto custom-scrollbar flex-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx( 183 SectionContent, 184 { 185 section, 186 activeSlug, 187 onClose, 188 currentUser, 189 onUploadRequested 190 } 191 ) }) 192 } 193 ) 194 ] }); 195}; 196export { 197 CarouselRow as C, 198 NetflixSectionCard as N, 199 SectionPreviewModal as S 200};
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.