1import { r as reactExports, j as jsxRuntimeExports } from "./vendor-react-Bay9Y7Lb.js"; 2import { a as api } from "./index-D0Bmh-UX.js"; 3import { bq as Coins, b9 as Settings, f3 as ToggleRight, f4 as ToggleLeft, bA as Eye, cL as RefreshCw, cc as Save, bv as CircleCheckBig, cJ as ShieldAlert, cs as BookOpen, b1 as CircleAlert, ch as Database } from "./vendor-dVNaLJx_.js"; 4import "./vendor-i18n-R-bMoYp_.js"; 5const DEFAULT_AD_SETTINGS = { 6 isEnabled: false, 7 publisherId: "", 8 enableAutoAds: false, 9 enableVignettes: false, 10 enableAnchors: false, 11 enableNonIntrusiveOnly: false, 12 adUnits: { 13 homeTop: { enabled: false, slotId: "" }, 14 homeBottom: { enabled: false, slotId: "" }, 15 watchSidebar: { enabled: false, slotId: "" }, 16 watchBottom: { enabled: false, slotId: "" }, 17 exploreSidebar: { enabled: false, slotId: "" }, 18 exploreList: { enabled: false, slotId: "" }, 19 converterBottom: { enabled: false, slotId: "" } 20 }, 21 excludeRoles: ["ADMIN"] 22}; 23const AdManager = ({ activeRole }) => { 24 const [config, setConfig] = reactExports.useState(DEFAULT_AD_SETTINGS); 25 const [isSaving, setIsSaving] = reactExports.useState(false); 26 const [saveStatus, setSaveStatus] = reactExports.useState("idle"); 27 const [activeTab, setActiveTab] = reactExports.useState("config"); 28 reactExports.useEffect(() => { 29 const fetchConfig = async () => { 30 try { 31 const res = await api.getSystemSetting("ad_settings"); 32 if (res && res.value) { 33 const dbConfig = res.value; 34 setConfig({ 35 ...DEFAULT_AD_SETTINGS, 36 ...dbConfig, 37 adUnits: { 38 ...DEFAULT_AD_SETTINGS.adUnits, 39 ...dbConfig.adUnits || {} 40 }, 41 excludeRoles: dbConfig.excludeRoles || ["ADMIN"] 42 }); 43 } 44 } catch (err) { 45 console.error("Failed to load ad_settings", err); 46 } 47 }; 48 fetchConfig(); 49 }, []); 50 const handleSave = async () => { 51 setIsSaving(true); 52 setSaveStatus("idle"); 53 try { 54 await api.saveSystemSetting("ad_settings", config); 55 setSaveStatus("success"); 56 setTimeout(() => setSaveStatus("idle"), 3e3); 57 } catch (err) { 58 console.error("Failed to save ad_settings", err); 59 setSaveStatus("error"); 60 } finally { 61 setIsSaving(false); 62 } 63 }; 64 const updateField = (key, value) => { 65 setConfig((prev) => ({ 66 ...prev, 67 [key]: value 68 })); 69 }; 70 const updateAdUnit = (slotKey, field, value) => { 71 setConfig((prev) => ({ 72 ...prev, 73 adUnits: { 74 ...prev.adUnits, 75 [slotKey]: { 76 ...prev.adUnits[slotKey], 77 [field]: value 78 } 79 } 80 })); 81 }; 82 const toggleRoleExclusion = (role) => { 83 setConfig((prev) => { 84 const current = prev.excludeRoles || []; 85 const updated = current.includes(role) ? current.filter((r) => r !== role) : [...current, role]; 86 return { 87 ...prev, 88 excludeRoles: updated 89 }; 90 }); 91 }; 92 const DevDebugInfo = ({ table, keyName, value }) => { 93 if (!(activeRole == null ? void 0 : activeRole.isSuperAdmin)) return null; 94 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-3 p-2 bg-zinc-100 dark:bg-zinc-950 border border-dashed border-zinc-300 dark:border-zinc-800 rounded-lg text-[10px] font-mono text-zinc-500 overflow-hidden", children: [
95 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2 items-center mb-0.5", children: [ 96 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-indigo-600 dark:text-indigo-400 font-bold flex items-center gap-1", children: [ 97 /* @__PURE__ */ jsxRuntimeExports.jsx(Database, { size: 8 }), 98 " ", 99 table 100 ] }), 101 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-400", children: "|" }), 102 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-600 dark:text-zinc-400", children: keyName }) 103 ] }), 104 value !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-emerald-600 dark:text-emerald-500 truncate font-medium", children: [ 105 "VAL: ", 106 JSON.stringify(value) 107 ] }) 108 ] }); 109 }; 110 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6 max-w-5xl", children: [ 111 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-indigo-50 dark:bg-indigo-900/20 p-5 rounded-2xl border border-indigo-200 dark:border-indigo-900/50 flex flex-col md:flex-row md:items-center justify-between gap-4", children: [
112 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 113 /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "font-extrabold text-indigo-950 dark:text-indigo-200 text-base mb-1 flex items-center gap-2", children: [ 114 /* @__PURE__ */ jsxRuntimeExports.jsx(Coins, { className: "text-indigo-650 dark:text-indigo-400", size: 20 }), 115 " Ad Monetization & Revenue Manager" 116 ] }), 117 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-indigo-900 dark:text-indigo-300 max-w-xl", children: "Configure Google AdSense integration, manage responsive ad placements across public pages, and toggle script rendering parameters dynamically." }) 118 ] }), 119 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2 self-start md:self-center", children: [ 120 /* @__PURE__ */ jsxRuntimeExports.jsx( 121 "button", 122 { 123 onClick: () => setActiveTab("config"), 124 className: `px-4 py-2 text-xs font-bold rounded-lg transition-all ${activeTab === "config" ? "bg-indigo-600 text-white shadow-md shadow-indigo-600/20" : "bg-zinc-105 dark:bg-zinc-800 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-200 dark:hover:bg-zinc-700"}`, 125 children: "Ad Settings" 126 } 127 ),
128 /* @__PURE__ */ jsxRuntimeExports.jsx( 129 "button", 130 { 131 onClick: () => setActiveTab("guide"), 132 className: `px-4 py-2 text-xs font-bold rounded-lg transition-all ${activeTab === "guide" ? "bg-indigo-600 text-white shadow-md shadow-indigo-600/20" : "bg-zinc-105 dark:bg-zinc-800 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-200 dark:hover:bg-zinc-700"}`, 133 children: "Setup Guide" 134 } 135 ) 136 ] }) 137 ] }), 138 activeTab === "config" ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-3 gap-6", children: [ 139 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "lg:col-span-2 space-y-6", children: [ 140 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-zinc-250 dark:border-zinc-800 rounded-2xl p-6 shadow-sm space-y-6", children: [ 141 /* @__PURE__ */ jsxRuntimeExports.jsxs("h4", { className: "text-sm font-extrabold text-zinc-900 dark:text-white border-b border-zinc-200 dark:border-zinc-800 pb-3 flex items-center gap-2", children: [
142 /* @__PURE__ */ jsxRuntimeExports.jsx(Settings, { size: 16, className: "text-zinc-600 dark:text-zinc-450" }), 143 " Global AdSense Settings" 144 ] }), 145 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-5", children: [ 146 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4 bg-zinc-50 dark:bg-zinc-800/40 rounded-xl border border-zinc-200 dark:border-zinc-800 flex items-center justify-between", children: [ 147 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 148 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm font-bold text-zinc-800 dark:text-zinc-200", children: "Global Monetization" }), 149 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs text-zinc-650 dark:text-zinc-400", children: "Inject AdSense elements on pages" }) 150 ] }), 151 /* @__PURE__ */ jsxRuntimeExports.jsx( 152 "button", 153 { 154 onClick: () => updateField("isEnabled", !config.isEnabled), 155 className: `p-1.5 rounded transition-colors ${config.isEnabled ? "text-emerald-600 dark:text-emerald-500" : "text-zinc-400"}`, 156 children: config.isEnabled ? /* @__PURE__ */ jsxRuntimeExports.jsx(ToggleRight, { size: 32 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ToggleLeft, { size: 32 }) 157 } 158 ) 159 ] }),
160 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4 bg-zinc-50 dark:bg-zinc-800/40 rounded-xl border border-zinc-200 dark:border-zinc-800 flex items-center justify-between", children: [ 161 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 162 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm font-bold text-zinc-800 dark:text-zinc-200", children: "AdSense Auto Ads" }), 163 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs text-zinc-650 dark:text-zinc-400", children: "Let Google place ads automatically" }) 164 ] }), 165 /* @__PURE__ */ jsxRuntimeExports.jsx( 166 "button", 167 { 168 onClick: () => updateField("enableAutoAds", !config.enableAutoAds), 169 className: `p-1.5 rounded transition-colors ${config.enableAutoAds ? "text-emerald-600 dark:text-emerald-500" : "text-zinc-400"}`, 170 children: config.enableAutoAds ? /* @__PURE__ */ jsxRuntimeExports.jsx(ToggleRight, { size: 32 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ToggleLeft, { size: 32 }) 171 } 172 ) 173 ] }) 174 ] }),
175 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [ 176 /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs font-bold text-zinc-700 dark:text-zinc-400 uppercase tracking-wider block", children: "AdSense Publisher Account ID (Client ID)" }), 177 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "relative", children: /* @__PURE__ */ jsxRuntimeExports.jsx( 178 "input", 179 { 180 type: "text", 181 placeholder: "e.g. ca-pub-xxxxxxxxxxxxxxxx", 182 value: config.publisherId, 183 onChange: (e) => updateField("publisherId", e.target.value.trim()), 184 className: "w-full px-4 py-2.5 bg-zinc-50 dark:bg-zinc-800 border border-zinc-200 dark:border-zinc-800 rounded-xl text-sm text-zinc-800 dark:text-zinc-100 focus:outline-none focus:ring-2 focus:ring-indigo-500 font-mono" 185 } 186 ) }), 187 /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-zinc-600 dark:text-zinc-400", children: [ 188 "Must start with ",
189 /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "bg-zinc-200 dark:bg-zinc-800 px-1 py-0.5 rounded font-mono text-zinc-800 dark:text-zinc-300", children: "ca-pub-" }), 190 ". This is required for both Auto Ads and individual ad units." 191 ] }) 192 ] }), 193 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-t border-zinc-200 dark:border-zinc-800 pt-5", children: [ 194 /* @__PURE__ */ jsxRuntimeExports.jsx("h5", { className: "text-xs font-bold text-indigo-750 dark:text-indigo-400 uppercase tracking-widest mb-3", children: "Google Page Format Features" }), 195 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [ 196 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-3 p-3 bg-indigo-50/40 dark:bg-indigo-950/20 hover:bg-indigo-50/80 dark:hover:bg-indigo-950/30 rounded-lg cursor-pointer border border-indigo-150 dark:border-indigo-900/40", children: [
197 /* @__PURE__ */ jsxRuntimeExports.jsx( 198 "input", 199 { 200 type: "checkbox", 201 checked: config.enableNonIntrusiveOnly || false, 202 onChange: (e) => { 203 const val = e.target.checked; 204 setConfig((prev) => ({ 205 ...prev, 206 enableNonIntrusiveOnly: val, 207 ...val ? { enableVignettes: false, enableAnchors: false } : {} 208 })); 209 }, 210 className: "rounded border-zinc-300 text-indigo-600 focus:ring-indigo-500 w-4 h-4" 211 } 212 ), 213 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 214 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs font-bold text-zinc-850 dark:text-zinc-200", children: "Enforce Non-Intrusive Placements" }), 215 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-zinc-650 dark:text-zinc-400", children: "Limit heights of manual ad containers and disable vignettes & overlay formats" }) 216 ] }) 217 ] }),
218 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: `flex items-center gap-3 p-3 bg-zinc-50 dark:bg-zinc-800/20 hover:bg-zinc-100/50 dark:hover:bg-zinc-800/40 rounded-lg cursor-pointer border border-zinc-200 dark:border-zinc-800 transition-all ${config.enableNonIntrusiveOnly ? "opacity-40 cursor-not-allowed" : ""}`, children: [ 219 /* @__PURE__ */ jsxRuntimeExports.jsx( 220 "input", 221 { 222 type: "checkbox", 223 disabled: config.enableNonIntrusiveOnly, 224 checked: config.enableNonIntrusiveOnly ? false : config.enableVignettes || false, 225 onChange: (e) => updateField("enableVignettes", e.target.checked), 226 className: "rounded border-zinc-300 text-indigo-600 focus:ring-indigo-500 w-4 h-4 disabled:opacity-50" 227 } 228 ), 229 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 230 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs font-bold text-zinc-850 dark:text-zinc-200", children: "Enable Vignettes" }),
231 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-zinc-650 dark:text-zinc-400", children: "Full-screen ads between page visits" }) 232 ] }) 233 ] }), 234 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: `flex items-center gap-3 p-3 bg-zinc-50 dark:bg-zinc-800/20 hover:bg-zinc-100/50 dark:hover:bg-zinc-800/40 rounded-lg cursor-pointer border border-zinc-200 dark:border-zinc-800 transition-all ${config.enableNonIntrusiveOnly ? "opacity-40 cursor-not-allowed" : ""}`, children: [ 235 /* @__PURE__ */ jsxRuntimeExports.jsx( 236 "input", 237 { 238 type: "checkbox", 239 disabled: config.enableNonIntrusiveOnly, 240 checked: config.enableNonIntrusiveOnly ? false : config.enableAnchors || false, 241 onChange: (e) => updateField("enableAnchors", e.target.checked), 242 className: "rounded border-zinc-300 text-indigo-650 focus:ring-indigo-500 w-4 h-4 disabled:opacity-50" 243 } 244 ),
245 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 246 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs font-bold text-zinc-850 dark:text-zinc-200", children: "Enable Anchor Ads" }), 247 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-zinc-650 dark:text-zinc-400", children: "Sticky ads at the bottom or top margin" }) 248 ] }) 249 ] }) 250 ] }) 251 ] }) 252 ] }), 253 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-zinc-250 dark:border-zinc-800 rounded-2xl p-6 shadow-sm space-y-6", children: [ 254 /* @__PURE__ */ jsxRuntimeExports.jsxs("h4", { className: "text-sm font-extrabold text-zinc-900 dark:text-white border-b border-zinc-200 dark:border-zinc-800 pb-3 flex items-center gap-2", children: [ 255 /* @__PURE__ */ jsxRuntimeExports.jsx(Eye, { size: 16, className: "text-zinc-600 dark:text-zinc-400" }), 256 " Manual Ad Placements" 257 ] }),
258 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-600 dark:text-zinc-400 -mt-2", children: "If Auto Ads are off or if you wish to run dedicated units in specific visual slots, configure them here." }), 259 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-4", children: Object.keys(config.adUnits).map((slotKey) => { 260 const unit = config.adUnits[slotKey]; 261 let label = slotKey; 262 let desc = ""; 263 if (slotKey === "homeTop") { 264 label = "Home Page (Top Banner)"; 265 desc = "Displayed below navigation header on Home"; 266 } else if (slotKey === "homeBottom") { 267 label = "Home Page (Bottom)"; 268 desc = "Displayed at bottom of homepage, perfect for Multiplex"; 269 } else if (slotKey === "watchSidebar") { 270 label = "Watch Page (Sidebar)"; 271 desc = "Placed in sidebar column beside related tracks/comments"; 272 } else if (slotKey === "watchBottom") { 273 label = "Watch Page (Bottom)"; 274 desc = "Underneath player & comments, matches Multiplex format"; 275 } else if (slotKey === "exploreSidebar") { 276 label = "Explore Page (Sidebar)"; 277 desc = "Beside search/category filters"; 278 } else if (slotKey === "exploreList") { 279 label = "Explore Page (In-List)"; 280 desc = "Interspersed in results list"; 281 } else if (slotKey === "converterBottom") { 282 label = "Converter Page (Bottom)"; 283 desc = "Placed clean below download dashboard"; 284 } 285 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4 bg-zinc-50 dark:bg-zinc-800/30 border border-zinc-200 dark:border-zinc-800/80 rounded-xl space-y-3", children: [
286 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [ 287 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 288 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-extrabold text-zinc-850 dark:text-zinc-200", children: label }), 289 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-zinc-600 dark:text-zinc-400 block", children: desc }) 290 ] }), 291 /* @__PURE__ */ jsxRuntimeExports.jsx( 292 "button", 293 { 294 onClick: () => updateAdUnit(slotKey, "enabled", !unit.enabled), 295 className: `p-1 rounded transition-colors ${unit.enabled ? "text-emerald-600 dark:text-emerald-500" : "text-zinc-400"}`, 296 children: unit.enabled ? /* @__PURE__ */ jsxRuntimeExports.jsx(ToggleRight, { size: 26 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ToggleLeft, { size: 26 }) 297 } 298 ) 299 ] }),
300 unit.enabled && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "relative", children: /* @__PURE__ */ jsxRuntimeExports.jsx( 301 "input", 302 { 303 type: "text", 304 placeholder: "Enter Ad Unit Slot ID (e.g. 1234567890)", 305 value: unit.slotId, 306 onChange: (e) => updateAdUnit(slotKey, "slotId", e.target.value.trim()), 307 className: "w-full px-3 py-1.5 bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-lg text-xs text-zinc-700 dark:text-zinc-300 font-mono focus:outline-none focus:ring-1 focus:ring-indigo-500" 308 } 309 ) }) 310 ] }, slotKey); 311 }) }) 312 ] }) 313 ] }), 314 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-6", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-2xl p-5 shadow-sm space-y-4 sticky top-6", children: [
315 /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "text-xs font-bold text-zinc-700 dark:text-zinc-450 uppercase tracking-widest", children: "Save & Synchronize" }), 316 /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-zinc-655 dark:text-zinc-400 leading-relaxed", children: [ 317 "Saving updates the centralized ", 318 /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "font-mono text-zinc-800 dark:text-zinc-300", children: "SystemSetting" }), 319 ", which triggers real-time pushes to the entire web cluster." 320 ] }), 321 /* @__PURE__ */ jsxRuntimeExports.jsxs( 322 "button", 323 { 324 onClick: handleSave, 325 disabled: isSaving, 326 className: "w-full py-3 bg-indigo-600 hover:bg-indigo-700 text-white rounded-xl text-sm font-extrabold flex items-center justify-center gap-2 shadow-lg shadow-indigo-500/25 active:scale-95 transition-all cursor-pointer disabled:opacity-50", 327 children: [ 328 isSaving ? /* @__P
328URE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: "animate-spin", size: 16 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Save, { size: 16 }), 329 isSaving ? "Saving Configurations..." : "Commit Settings" 330 ] 331 } 332 ), 333 saveStatus === "success" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-3 bg-emerald-50 dark:bg-emerald-950/20 text-emerald-800 dark:text-emerald-350 border border-emerald-150 dark:border-emerald-900/40 rounded-xl text-xs flex items-center gap-2", children: [ 334 /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheckBig, { size: 16 }), 335 " settings committed and cluster notified." 336 ] }), 337 saveStatus === "error" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-3 bg-red-50 dark:bg-red-950/20 text-red-805 dark:text-red-350 border border-red-150 dark:border-red-900/40 rounded-xl text-xs flex items-center gap-2", children: [ 338 /* @__PURE__ */ jsxRuntimeExports.jsx(ShieldAlert, { size: 16 }), 339 " Error saving configuration to database." 340 ] }),
341 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-t border-zinc-200 dark:border-zinc-800 pt-4 space-y-3", children: [ 342 /* @__PURE__ */ jsxRuntimeExports.jsx("h5", { className: "text-[10px] font-bold text-zinc-700 dark:text-zinc-450 uppercase tracking-wider", children: "Exclude User Roles" }), 343 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] text-zinc-600 dark:text-zinc-400 leading-relaxed", children: "Roles selected below will completely bypass script loading (e.g. ad-free system testing)." }), 344 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-2 pt-1", children: ["ADMIN", "USER", "GUEST"].map((role) => { 345 var _a; 346 const isChecked = ((_a = config.excludeRoles) == null ? void 0 : _a.includes(role)) || false; 347 return /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-2.5 text-xs text-zinc-800 dark:text-zinc-300 cursor-pointer", children: [ 348 /* @__PURE__ */ jsxRuntimeExports.jsx( 349 "input", 350 { 351 type: "checkbox", 352 checked: isChecked, 353 onChange: () => toggleRoleExclusion(role), 354 className: "rounded border-zinc-300 text-indigo-600 focus:ring-indigo-500" 355 } 356 ),
357 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-semibold", children: role }) 358 ] }, role); 359 }) }) 360 ] }), 361 /* @__PURE__ */ jsxRuntimeExports.jsx(DevDebugInfo, { table: "SystemSetting", keyName: "ad_settings", value: config }) 362 ] }) }) 363 ] }) : ( 364 /* Setup Guide Tab */ 365 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-2xl p-6 shadow-sm space-y-6", children: [ 366 /* @__PURE__ */ jsxRuntimeExports.jsxs("h4", { className: "text-sm font-extrabold text-zinc-900 dark:text-white border-b border-zinc-200 dark:border-zinc-800 pb-3 flex items-center gap-2", children: [ 367 /* @__PURE__ */ jsxRuntimeExports.jsx(BookOpen, { size: 16, className: "text-zinc-600" }), 368 " Connecting Google AdSense to HamieNET" 369 ] }), 370 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4 text-xs text-zinc-700 dark:text-zinc-300 leading-relaxed", children: [
371 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-3", children: [ 372 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-shrink-0 w-5 h-5 rounded-full bg-indigo-100 dark:bg-indigo-900/40 text-indigo-900 dark:text-indigo-300 flex items-center justify-center font-bold font-mono", children: "1" }), 373 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 374 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "font-bold text-zinc-900 dark:text-zinc-100 text-sm mb-0.5", children: "Locate your AdSense Publisher ID" }), 375 /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [ 376 "Log in to your ", 377 /* @__PURE__ */ jsxRuntimeExports.jsx("a", { href: "https://adsense.google.com", target: "_blank", rel: "noreferrer", className: "text-indigo-600 dark:text-indigo-400 hover:underline", children: "Google AdSense Dashboard" }), 378 ". Go to Account > Settings > Account information. Copy your Publisher ID (starts with ",
379 /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "bg-zinc-200 dark:bg-zinc-800 px-1 py-0.5 rounded font-mono text-zinc-800 dark:text-zinc-300", children: "ca-pub-xxxxxxxxxxxxxxxx" }), 380 ")." 381 ] }) 382 ] }) 383 ] }), 384 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-3", children: [ 385 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-shrink-0 w-5 h-5 rounded-full bg-indigo-100 dark:bg-indigo-900/40 text-indigo-900 dark:text-indigo-300 flex items-center justify-center font-bold font-mono", children: "2" }), 386 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 387 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "font-bold text-zinc-900 dark:text-zinc-100 text-sm mb-0.5", children: "Enable AdSense Globally in this panel" }), 388 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: 'Toggle "Global Monetization" on the settings tab, paste your publisher ID, and click "Commit Settings". This injects the official Google JS library in the head element of the page for users.' }) 389 ] }) 390 ] }),
391 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-3", children: [ 392 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-shrink-0 w-5 h-5 rounded-full bg-indigo-100 dark:bg-indigo-900/40 text-indigo-900 dark:text-indigo-300 flex items-center justify-center font-bold font-mono", children: "3" }), 393 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 394 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "font-bold text-zinc-900 dark:text-zinc-100 text-sm mb-0.5", children: "Choose between Auto Ads and Manual Ads" }), 395 /* @__PURE__ */ jsxRuntimeExports.jsxs("ul", { className: "list-disc pl-5 space-y-1.5 mt-1 text-zinc-700 dark:text-zinc-350", children: [ 396 /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [ 397 /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Auto Ads:" }), 398 " Enable this to let Google automatically scan the pages of HamieNET and inject ads dynamically in headers, margin sidebars, and native text streams. Perfect for effortless setup." 399 ] }),
400 /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [ 401 /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Manual Placements:" }), 402 " Turn Auto Ads off and toggle specific slots in the settings panel (like Watch Page Sidebar). Add the exact Slot ID generated inside AdSense > Ads > By Ad Unit. We support responsive display formats and multiplex (related post grid) recommendations." 403 ] }), 404 /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [ 405 /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Non-Intrusive Mode:" }), 406 " Enforce Non-Intrusive Placements to disable vignettes and anchors globally, set manual ad components to a compact 90px height limit, and request horizontal banner formats only." 407 ] }) 408 ] }) 409 ] }) 410 ] }), 411 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-3", children: [ 412 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-shrink-0 w-5 h-5 rounded-full bg-indigo-100 dark:bg-indigo-900/40 text-indigo-900 dark:text-indigo-300 flex items-center justify-center font-bold font-mono", children: "4" }),
413 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 414 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "font-bold text-zinc-900 dark:text-zinc-100 text-sm mb-0.5", children: "Verify ads.txt Placement" }), 415 /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [ 416 "AdSense requires an ", 417 /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "font-mono text-zinc-800 dark:text-zinc-200 bg-zinc-100 dark:bg-zinc-800/40 px-1 border border-zinc-200 dark:border-zinc-800 rounded", children: "ads.txt" }), 418 " file in the public root. Make sure it is placed in the static assets path ", 419 /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "font-mono", children: "/web/public/ads.txt" }), 420 " of the deployer containing your publisher key:" 421 ] }), 422 /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "p-3 bg-zinc-100 dark:bg-zinc-800 rounded-lg font-mono text-[10px] mt-2 border border-zinc-250 dark:border-zinc-800 text-zinc-900 dark:text-zinc-250 select-all", children: "google.com, pub-XXXXXXXXXXXXXXXX, DIRECT, f08c47fec0942fa0" }) 423 ] }) 424 ] }),
425 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-6 p-4 bg-yellow-50 dark:bg-yellow-950/20 border border-yellow-200 dark:border-yellow-900/30 rounded-xl text-yellow-950 dark:text-yellow-350 flex gap-2.5", children: [ 426 /* @__PURE__ */ jsxRuntimeExports.jsx(CircleAlert, { className: "flex-shrink-0 text-yellow-600 dark:text-yellow-400", size: 18 }), 427 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 428 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-extrabold text-sm block mb-0.5 text-yellow-905 dark:text-yellow-200", children: "Ad Blocking Extensions Notice" }), 429 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-yellow-900 dark:text-yellow-300", children: "If you have an active ad blocker installed on your browser, mock slots and Google script injection will fail to report status correctly. Disable ad blockers for this domain while verifying configurations." }) 430 ] }) 431 ] }) 432 ] }) 433 ] }) 434 ) 435 ] }); 436}; 437export { 438 AdManager as default 439};
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.