+12








fcd7c979df
Co-authored-by: Artur <145776561+arturict@users.noreply.github.com> Co-authored-by: arturict <arturict@users.noreply.github.com> Co-authored-by: Thomas <thomas@ajnart.fr> Co-authored-by: Afonso Jorge Ramos <afonsojorgeramos@gmail.com> Co-authored-by: Danura30082 <danura30082+github@gmail.com> Co-authored-by: Kushie <122986913+kushiemoon-dev@users.noreply.github.com> Co-authored-by: ajnart <thomas@ajnart.fr> Co-authored-by: ajnart <thomas@ajnart.dev> Co-authored-by: chenjun <chenjun@foxmail.com> Co-authored-by: Wikibear <wikibear@users.noreply.github.com> Co-authored-by: Bergasha <bergasha@gmail.com> Co-authored-by: leafyelin <43306196+leafyelin@users.noreply.github.com> Co-authored-by: Lucas Araujo <lucas.lra@gmail.com> Co-authored-by: GreenMonito <86085570+GreenMonito@users.noreply.github.com> Co-authored-by: Nerdy-Technician <roffo@nerdy-technician.social> Co-authored-by: Jun <34545896+jcstrong@users.noreply.github.com> Co-authored-by: Edmond Abraham <54119952+gitedmond@users.noreply.github.com> Co-authored-by: thrawnx <tight.bulb9384@fastmail.com> Co-authored-by: Chris <58918656+nordada@users.noreply.github.com> Co-authored-by: yi111 <153097222+Yi-111-a@users.noreply.github.com> Co-authored-by: Yanis <naamaneyanis@gmail.com> Co-authored-by: Wikibear <me@sej.de> Co-authored-by: alessiottavo <93441886+alessiottavo@users.noreply.github.com>
78 lines
2.7 KiB
TypeScript
78 lines
2.7 KiB
TypeScript
"use client";
|
|
|
|
import { usePathname } from "next/navigation";
|
|
import { useEffect, useRef } from "react";
|
|
|
|
type Placement = "toc" | "inline" | "banner" | "site-footer";
|
|
|
|
/** Responsive placements are mutually exclusive: never request a hidden ad. */
|
|
export function Carbon({ placement = "banner" }: { placement?: Placement }) {
|
|
const ref = useRef<HTMLDivElement>(null);
|
|
const pathname = usePathname();
|
|
|
|
const hidden =
|
|
pathname === "/" || (placement === "site-footer" && /^\/workshop\/(?!admin\/?$)[^/]+\/?$/.test(pathname ?? ""));
|
|
|
|
useEffect(() => {
|
|
const host = ref.current;
|
|
if (!host || hidden) return;
|
|
if (process.env.NODE_ENV !== "production" && process.env.NEXT_PUBLIC_ENABLE_CARBON_ADS !== "true") return;
|
|
const desktop = window.matchMedia("(min-width: 1280px)");
|
|
|
|
let pendingLoad: ReturnType<typeof setTimeout> | undefined;
|
|
// Carbon responses can outlive the script that requested them. Keep the newest
|
|
// creative if an earlier navigation or breakpoint request finishes late.
|
|
const observer = new MutationObserver(() => {
|
|
const creatives = host.querySelectorAll('[id="carbonads"]');
|
|
for (const creative of Array.from(creatives).slice(0, -1)) creative.remove();
|
|
});
|
|
observer.observe(host, { childList: true, subtree: true });
|
|
|
|
function update() {
|
|
clearTimeout(pendingLoad);
|
|
if (!host) return;
|
|
const visible =
|
|
placement === "banner" ||
|
|
placement === "site-footer" ||
|
|
(placement === "toc" && desktop.matches) ||
|
|
(placement === "inline" && !desktop.matches);
|
|
if (!visible) {
|
|
host.replaceChildren();
|
|
return;
|
|
}
|
|
if (host.querySelector("script")) return;
|
|
// Defer until after effect cleanup, avoiding duplicate requests during
|
|
// React Strict Mode's setup/cleanup/setup cycle.
|
|
pendingLoad = setTimeout(() => {
|
|
if (!host.isConnected || host.querySelector("script")) return;
|
|
const script = document.createElement("script");
|
|
script.id = "_carbonads_js";
|
|
script.async = true;
|
|
script.src = "https://cdn.carbonads.com/carbon.js?serve=CWBDTKQM&placement=homarrdev&format=cover";
|
|
host.appendChild(script);
|
|
}, 0);
|
|
}
|
|
|
|
update();
|
|
desktop.addEventListener("change", update);
|
|
return () => {
|
|
clearTimeout(pendingLoad);
|
|
observer.disconnect();
|
|
desktop.removeEventListener("change", update);
|
|
host.replaceChildren();
|
|
};
|
|
}, [pathname, placement, hidden]);
|
|
|
|
if (hidden) return null;
|
|
|
|
return (
|
|
<aside
|
|
aria-label="Advertisement"
|
|
className={`homarr-carbon homarr-carbon-${placement}`}
|
|
data-visual-test="blackout"
|
|
>
|
|
<div ref={ref} />
|
|
</aside>
|
|
);
|
|
}
|