mirror of
https://github.com/kamranahmedse/developer-roadmap.git
synced 2025-08-16 14:14:11 +02:00
Add support for multiple ads
This commit is contained in:
@@ -1,36 +1,57 @@
|
|||||||
import { useStore } from '@nanostores/preact';
|
import { useStore } from '@nanostores/preact';
|
||||||
import { useEffect, useState } from 'preact/hooks';
|
import { useEffect, useState } from 'preact/hooks';
|
||||||
import CloseIcon from '../icons/close.svg';
|
import CloseIcon from '../icons/close.svg';
|
||||||
|
import { httpGet } from '../lib/http';
|
||||||
import { sponsorHidden } from '../stores/page';
|
import { sponsorHidden } from '../stores/page';
|
||||||
|
|
||||||
export type PageSponsorType = {
|
export type PageSponsorType = {
|
||||||
url: string;
|
|
||||||
title: string;
|
|
||||||
imageUrl: string;
|
|
||||||
description: string;
|
|
||||||
company: string;
|
company: string;
|
||||||
page: string;
|
description: string;
|
||||||
|
imageUrl: string;
|
||||||
|
pageUrl: string;
|
||||||
|
title: string;
|
||||||
|
url: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type V1GetSponsorResponse = {
|
||||||
|
href?: string;
|
||||||
|
sponsor?: PageSponsorType;
|
||||||
};
|
};
|
||||||
|
|
||||||
type PageSponsorProps = {
|
type PageSponsorProps = {
|
||||||
sponsors?: PageSponsorType[];
|
gaPageIdentifier?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function PageSponsor(props: PageSponsorProps) {
|
export function PageSponsor(props: PageSponsorProps) {
|
||||||
const { sponsors = [] } = props;
|
const { gaPageIdentifier } = props;
|
||||||
const $isSponsorHidden = useStore(sponsorHidden);
|
const $isSponsorHidden = useStore(sponsorHidden);
|
||||||
const [sponsor, setSponsor] = useState<PageSponsorType>();
|
const [sponsor, setSponsor] = useState<PageSponsorType>();
|
||||||
|
|
||||||
if (sponsors.length === 0) {
|
const loadSponsor = async () => {
|
||||||
return null;
|
const { response, error } = await httpGet<V1GetSponsorResponse>(
|
||||||
}
|
`${import.meta.env.PUBLIC_API_URL}/v1-get-sponsor`,
|
||||||
|
{
|
||||||
|
href: window.location.pathname,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
function loadSponsor() {
|
if (error) {
|
||||||
console.log('loadSponsor');
|
console.error(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const sponsorIndex = Math.floor(Math.random() * sponsors.length);
|
if (!response?.sponsor) {
|
||||||
setSponsor(sponsors[sponsorIndex]);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setSponsor(response.sponsor);
|
||||||
|
|
||||||
|
window.fireEvent({
|
||||||
|
category: 'SponsorImpression',
|
||||||
|
action: `${response.sponsor?.company} Impression`,
|
||||||
|
label: `${gaPageIdentifier} / ${response.sponsor?.company} Link`,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// We load the sponsor after 1second of the page load
|
// We load the sponsor after 1second of the page load
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -42,7 +63,7 @@ export function PageSponsor(props: PageSponsorProps) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { url, title, imageUrl, description, company, page } = sponsor;
|
const { url, title, imageUrl, description, company, pageUrl } = sponsor;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<a
|
<a
|
||||||
@@ -54,7 +75,7 @@ export function PageSponsor(props: PageSponsorProps) {
|
|||||||
window.fireEvent({
|
window.fireEvent({
|
||||||
category: 'SponsorClick',
|
category: 'SponsorClick',
|
||||||
action: `${company} Redirect`,
|
action: `${company} Redirect`,
|
||||||
label: `${page} / ${company} Link`,
|
label: `${gaPageIdentifier} / ${company} Link`,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@@ -1,57 +0,0 @@
|
|||||||
---
|
|
||||||
import type { GAEventType } from '../Analytics/analytics';
|
|
||||||
import Icon from '../AstroIcon.astro';
|
|
||||||
|
|
||||||
export type SponsorType = {
|
|
||||||
url: string;
|
|
||||||
title: string;
|
|
||||||
imageUrl: string;
|
|
||||||
description: string;
|
|
||||||
event: GAEventType;
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface Props {
|
|
||||||
sponsor: SponsorType;
|
|
||||||
}
|
|
||||||
|
|
||||||
const {
|
|
||||||
sponsor: { title, url, description, imageUrl, event },
|
|
||||||
} = Astro.props;
|
|
||||||
---
|
|
||||||
|
|
||||||
<script src='./sponsor.js'></script>
|
|
||||||
|
|
||||||
<a
|
|
||||||
href={url}
|
|
||||||
id='sponsor-ad'
|
|
||||||
target='_blank'
|
|
||||||
rel='noopener sponsored nofollow'
|
|
||||||
ga-category={event?.category}
|
|
||||||
ga-action={event?.action}
|
|
||||||
ga-label={event?.label}
|
|
||||||
class='fixed bottom-[15px] right-[15px] outline-transparent z-50 bg-white max-w-[350px] shadow-lg outline-0 hidden'
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class='absolute top-1.5 right-1.5 text-gray-300 hover:text-gray-800'
|
|
||||||
aria-label='Close'
|
|
||||||
close-sponsor
|
|
||||||
>
|
|
||||||
<Icon icon='close' class='h-4' />
|
|
||||||
</button>
|
|
||||||
<img src={imageUrl} class='h-[150px] lg:h-[169px]' alt='Sponsor Banner' />
|
|
||||||
<span class='text-sm flex flex-col justify-between'>
|
|
||||||
<span class='p-[10px]'>
|
|
||||||
<span class='font-semibold mb-0.5 block'>{title}</span>
|
|
||||||
<span class='text-gray-500 block'>{description}</span>
|
|
||||||
</span>
|
|
||||||
<span class='sponsor-footer'>Partner Content</span>
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
document.querySelector('[close-sponsor]')?.addEventListener('click', (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
document.getElementById('sponsor-ad')?.classList.add('hidden');
|
|
||||||
});
|
|
||||||
</script>
|
|
@@ -1,22 +0,0 @@
|
|||||||
import { sponsorHidden } from '../../stores/page';
|
|
||||||
|
|
||||||
function showHideSponsor(shouldHide) {
|
|
||||||
const ad = document.querySelector('#sponsor-ad');
|
|
||||||
if (!ad) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shouldHide) {
|
|
||||||
ad.classList.add('hidden');
|
|
||||||
ad.classList.remove('flex');
|
|
||||||
} else {
|
|
||||||
ad.classList.remove('hidden');
|
|
||||||
ad.classList.add('flex');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sponsorHidden.listen(showHideSponsor);
|
|
||||||
|
|
||||||
window.setTimeout(() => {
|
|
||||||
showHideSponsor(false);
|
|
||||||
}, 500);
|
|
@@ -11,6 +11,8 @@ import '../styles/global.css';
|
|||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
title: string;
|
title: string;
|
||||||
|
// This isn't used anywhere except for the sponsor event labels
|
||||||
|
briefTitle?: string;
|
||||||
redirectUrl?: string;
|
redirectUrl?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
keywords?: string[];
|
keywords?: string[];
|
||||||
@@ -23,6 +25,7 @@ export interface Props {
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
title = siteConfig.title,
|
title = siteConfig.title,
|
||||||
|
briefTitle,
|
||||||
description = siteConfig.description,
|
description = siteConfig.description,
|
||||||
keywords = siteConfig.keywords,
|
keywords = siteConfig.keywords,
|
||||||
noIndex = false,
|
noIndex = false,
|
||||||
@@ -41,6 +44,12 @@ const canonicalUrl = givenCanonical || currentPageAbsoluteUrl;
|
|||||||
const commitUrl = `https://github.com/kamranahmedse/developer-roadmap/commit/${
|
const commitUrl = `https://github.com/kamranahmedse/developer-roadmap/commit/${
|
||||||
import.meta.env.GITHUB_SHA
|
import.meta.env.GITHUB_SHA
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
|
// e.g. frontend:react or best-practices:frontend-performance
|
||||||
|
const gaPageIdentifier = Astro.url.pathname
|
||||||
|
.replace(/^\//, '')
|
||||||
|
.replace(/\/$/, '')
|
||||||
|
.replace(/\//g, ':');
|
||||||
---
|
---
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
@@ -140,7 +149,7 @@ const commitUrl = `https://github.com/kamranahmedse/developer-roadmap/commit/${
|
|||||||
<Analytics />
|
<Analytics />
|
||||||
<Authenticator />
|
<Authenticator />
|
||||||
<PageProgress client:idle />
|
<PageProgress client:idle />
|
||||||
<PageSponsor sponsors={sponsors || []} client:idle />
|
<PageSponsor gaPageIdentifier={briefTitle || gaPageIdentifier} client:idle />
|
||||||
|
|
||||||
<slot name='after-footer' />
|
<slot name='after-footer' />
|
||||||
</body>
|
</body>
|
||||||
|
@@ -61,6 +61,7 @@ const contentContributionLink = `https://github.com/kamranahmedse/developer-road
|
|||||||
<BaseLayout
|
<BaseLayout
|
||||||
permalink={`/${roadmapId}`}
|
permalink={`/${roadmapId}`}
|
||||||
title={roadmapData?.seo?.title}
|
title={roadmapData?.seo?.title}
|
||||||
|
briefTitle={roadmapData?.briefTitle}
|
||||||
description={roadmapData.seo.description}
|
description={roadmapData.seo.description}
|
||||||
keywords={roadmapData.seo.keywords}
|
keywords={roadmapData.seo.keywords}
|
||||||
sponsors={roadmapData.sponsors}
|
sponsors={roadmapData.sponsors}
|
||||||
|
@@ -53,6 +53,7 @@ const contentContributionLink = `https://github.com/kamranahmedse/developer-road
|
|||||||
<BaseLayout
|
<BaseLayout
|
||||||
permalink={`/best-practices/${bestPracticeId}`}
|
permalink={`/best-practices/${bestPracticeId}`}
|
||||||
title={bestPracticeData?.seo?.title}
|
title={bestPracticeData?.seo?.title}
|
||||||
|
briefTitle={bestPracticeData?.briefTitle}
|
||||||
description={bestPracticeData.seo.description}
|
description={bestPracticeData.seo.description}
|
||||||
keywords={bestPracticeData.seo.keywords}
|
keywords={bestPracticeData.seo.keywords}
|
||||||
sponsors={bestPracticeData.sponsors}
|
sponsors={bestPracticeData.sponsors}
|
||||||
|
Reference in New Issue
Block a user