Files
homarr/apps/docs/src/components/carbon.tsx
T
+12 fcd7c979df feat!: release v2 (#6545)
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>
2026-10-02 21:00:14 +02:00

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>
);
}