Skip to content

Commit 08543a1

Browse files
authored
Docs: update lading page (banner & latest release fetch) (#883)
* feat: add banner to landing page * fix: revert latest news id change * feat: fetch latest release version from gh api
1 parent c5cac69 commit 08543a1

File tree

2 files changed

+146
-4
lines changed

2 files changed

+146
-4
lines changed
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import React, { useEffect, useState, useRef } from "react";
2+
3+
export interface AdBannerProps {
4+
zoneId: string;
5+
contentId: string;
6+
}
7+
8+
export const AdBanner = ({ zoneId, contentId }: AdBannerProps) => {
9+
const [isAdLoaded, setIsAdLoaded] = useState(false);
10+
const adContainerRef = useRef<HTMLDivElement>(null);
11+
const adContentRef = useRef<HTMLDivElement>(null);
12+
const adDetectedRef = useRef(false);
13+
14+
useEffect(() => {
15+
const adContainer = adContainerRef.current;
16+
if (!adContainer) return;
17+
18+
const insElement = adContainer.querySelector("ins");
19+
if (!insElement) return;
20+
21+
const checkForAd = () => {
22+
if (adDetectedRef.current) return true;
23+
24+
const isLoaded =
25+
insElement.getAttribute("data-content-loaded") === "1" ||
26+
insElement.querySelector(".revive-banner") !== null ||
27+
insElement.querySelector("a.revive-banner") !== null ||
28+
(insElement.children.length > 0 && insElement.offsetHeight > 10);
29+
30+
if (isLoaded) {
31+
adDetectedRef.current = true;
32+
setIsAdLoaded(true);
33+
return true;
34+
}
35+
return false;
36+
};
37+
38+
const observer = new MutationObserver(() => {
39+
checkForAd();
40+
});
41+
42+
observer.observe(insElement, {
43+
childList: true,
44+
subtree: true,
45+
attributes: true,
46+
attributeFilter: ["data-content-loaded", "style", "class", "id"],
47+
});
48+
49+
observer.observe(adContainer, {
50+
childList: true,
51+
subtree: true,
52+
attributes: true,
53+
});
54+
55+
const handleAdLoaded = () => {
56+
if (!adDetectedRef.current) {
57+
adDetectedRef.current = true;
58+
setIsAdLoaded(true);
59+
}
60+
};
61+
62+
const eventName = `content-${contentId}-loaded`;
63+
document.addEventListener(eventName, handleAdLoaded);
64+
65+
checkForAd();
66+
67+
const intervals = [
68+
setTimeout(checkForAd, 500),
69+
setTimeout(checkForAd, 1000),
70+
setTimeout(checkForAd, 2000),
71+
setTimeout(checkForAd, 3000),
72+
setTimeout(checkForAd, 5000),
73+
];
74+
75+
return () => {
76+
observer.disconnect();
77+
intervals.forEach(clearTimeout);
78+
document.removeEventListener(eventName, handleAdLoaded);
79+
};
80+
}, [contentId]);
81+
82+
useEffect(() => {
83+
const container = adContainerRef.current;
84+
const content = adContentRef.current;
85+
if (!container || !content) return;
86+
87+
if (isAdLoaded) {
88+
const updateHeight = () => {
89+
const height = content.scrollHeight || content.offsetHeight || 100;
90+
container.style.maxHeight = `${Math.max(height, 100)}px`;
91+
container.style.overflow = "visible";
92+
};
93+
requestAnimationFrame(updateHeight);
94+
setTimeout(updateHeight, 100);
95+
setTimeout(updateHeight, 500);
96+
} else {
97+
container.style.maxHeight = "0px";
98+
container.style.overflow = "hidden";
99+
}
100+
}, [isAdLoaded]);
101+
102+
return (
103+
<div
104+
ref={adContainerRef}
105+
className="w-full transition-all duration-500 ease-in-out"
106+
style={{
107+
opacity: isAdLoaded ? 1 : 0,
108+
}}
109+
>
110+
<div ref={adContentRef} className="w-full">
111+
<ins data-content-zoneid={zoneId} data-content-id={contentId}></ins>
112+
</div>
113+
<script
114+
async
115+
src="//revive-adserver.swmansion.com/www/assets/js/lib.js"
116+
></script>
117+
</div>
118+
);
119+
};

landing/src/components/ui/Header.tsx

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@ import React, { useEffect, useState, useRef, useImperativeHandle } from "react";
22
import { cn } from "@/lib/utils";
33
import { Logo } from "@/components/ui/Logo";
44
import { Github } from "@/components/ui/Github";
5+
import { AdBanner } from "@/components/ui/AdBanner";
56
import { getStorageValue } from "@/lib/utils";
67

78
export interface HeaderProps extends React.HTMLAttributes<HTMLElement> {}
89

9-
const LATEST_NEWS_ID = "v0.4.2";
10+
const DEFAULT_LATEST_NEWS_ID = "v0.5.0";
11+
const GITHUB_API_URL =
12+
"https://api.github.com/repos/software-mansion/live-debugger/releases/latest";
1013

1114
const navItems = [
1215
{ name: "Features", href: "#features" },
@@ -44,15 +47,34 @@ const Header = React.forwardRef<HTMLElement, HeaderProps>(
4447
const [isScrolled, setIsScrolled] = useState(false);
4548
const [showIndicator, setShowIndicator] = useState(false);
4649
const [activeTheme, setActiveTheme] = useState("dark");
50+
const [latestNewsId, setLatestNewsId] = useState(DEFAULT_LATEST_NEWS_ID);
4751

4852
const localHeaderRef = useRef<HTMLElement>(null);
4953
useImperativeHandle(ref, () => localHeaderRef.current!);
5054

5155
useEffect(() => {
52-
const seenVersion = getStorageValue("seenNewsVersion", null);
53-
setShowIndicator(seenVersion !== LATEST_NEWS_ID);
56+
const fetchLatestRelease = async () => {
57+
try {
58+
const response = await fetch(GITHUB_API_URL);
59+
if (response.ok) {
60+
const data = await response.json();
61+
if (data.tag_name) {
62+
setLatestNewsId(data.tag_name);
63+
}
64+
}
65+
} catch (error) {
66+
console.error("Failed to fetch latest release:", error);
67+
}
68+
};
69+
70+
fetchLatestRelease();
5471
}, []);
5572

73+
useEffect(() => {
74+
const seenVersion = getStorageValue("seenNewsVersion", null);
75+
setShowIndicator(seenVersion !== latestNewsId);
76+
}, [latestNewsId]);
77+
5678
useEffect(() => {
5779
const handleScroll = () => {
5880
const scrollY = window.scrollY;
@@ -101,6 +123,7 @@ const Header = React.forwardRef<HTMLElement, HeaderProps>(
101123
)}
102124
{...props}
103125
>
126+
<AdBanner zoneId="3" contentId="ea15c4216158c4097b65fe6504a4b3b7" />
104127
<div className="mx-auto flex h-20 w-full max-w-[1360px] items-center justify-between px-7 sm:px-8">
105128
<a href="#hero" className="mr-6 flex items-center gap-2">
106129
<Logo className="size-36 sm:size-42 md:size-45" />
@@ -124,7 +147,7 @@ const Header = React.forwardRef<HTMLElement, HeaderProps>(
124147
if (item.href === "#whatsnew") {
125148
setShowIndicator(false);
126149
try {
127-
localStorage.setItem("seenNewsVersion", LATEST_NEWS_ID);
150+
localStorage.setItem("seenNewsVersion", latestNewsId);
128151
} catch (error) {
129152
console.error("Error setting localStorage", error);
130153
}

0 commit comments

Comments
 (0)