first run at responsive ads
This commit is contained in:
parent
85142fe932
commit
e6436dd3ae
13 changed files with 273 additions and 204 deletions
|
|
@ -55,6 +55,7 @@
|
|||
"@storybook/theming": "^7.4.2",
|
||||
"@sveltejs/vite-plugin-svelte": "^2.4.1",
|
||||
"@tsconfig/svelte": "^4.0.1",
|
||||
"@types/google-publisher-tag": "^1.20240219.0",
|
||||
"@types/gtag.js": "^0.0.12",
|
||||
"@types/mdx": "^2.0.5",
|
||||
"@types/proper-url-join": "^2.1.1",
|
||||
|
|
|
|||
31
src/components/AdSlot/@types/ads.ts
Normal file
31
src/components/AdSlot/@types/ads.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
export type AdType =
|
||||
| 'leaderboard'
|
||||
| 'sponsorlogo'
|
||||
| 'native'
|
||||
| 'mpu'
|
||||
| 'billboard';
|
||||
|
||||
export type PlacementName =
|
||||
| 'reuters_desktop_leaderboard_atf'
|
||||
| 'reuters_mobile_leaderboard'
|
||||
| 'reuters_desktop_native_1'
|
||||
| 'reuters_mobile_mpu_1'
|
||||
| 'reuters_sponsorlogo'
|
||||
| 'reuters_billboard_desktop';
|
||||
|
||||
export type DesktopPlacementName =
|
||||
| 'reuters_desktop_leaderboard_atf'
|
||||
| 'reuters_desktop_native_1'
|
||||
| 'reuters_sponsorlogo'
|
||||
| 'reuters_billboard_desktop';
|
||||
|
||||
export type MobilePlacementName<DesktopPlacementName extends string> =
|
||||
DesktopPlacementName extends 'reuters_desktop_leaderboard_atf'
|
||||
? 'reuters_mobile_leaderboard'
|
||||
: DesktopPlacementName extends 'reuters_desktop_native_1'
|
||||
? 'reuters_mobile_mpu_1'
|
||||
: DesktopPlacementName extends 'reuters_sponsorlogo'
|
||||
? 'reuters_sponsorlogo'
|
||||
: DesktopPlacementName extends 'reuters_billboard_desktop'
|
||||
? 'reuters_mobile_mpu_1'
|
||||
: never;
|
||||
|
|
@ -2,35 +2,7 @@
|
|||
import { onMount } from 'svelte';
|
||||
import { loadBootstrap } from './adScripts/bootstrap';
|
||||
import { loadScript } from './adScripts/loadScript';
|
||||
import { throttle } from 'lodash-es';
|
||||
|
||||
let lastScroll = 0;
|
||||
let showManagePreferences = true;
|
||||
|
||||
const togglePrefs = (on = true) => {
|
||||
const btn = document.getElementById('ot-sdk-btn-floating');
|
||||
if (!btn) return;
|
||||
if (on) {
|
||||
showManagePreferences = true;
|
||||
btn.style.bottom = '';
|
||||
} else {
|
||||
showManagePreferences = false;
|
||||
btn.style.bottom = '-5rem';
|
||||
}
|
||||
};
|
||||
|
||||
const handleScroll = () => {
|
||||
if (lastScroll > window.scrollY) {
|
||||
if (!showManagePreferences) {
|
||||
togglePrefs(true);
|
||||
}
|
||||
} else {
|
||||
if (showManagePreferences && window.scrollY > 250) {
|
||||
togglePrefs(false);
|
||||
}
|
||||
}
|
||||
lastScroll = window.scrollY;
|
||||
};
|
||||
import OneTrust from './OneTrust.svelte';
|
||||
|
||||
onMount(() => {
|
||||
window.graphicsAdQueue = window.graphicsAdQueue || [];
|
||||
|
|
@ -38,9 +10,6 @@
|
|||
'https://graphics.thomsonreuters.com/cdn/js/bootstrap.static.js',
|
||||
loadBootstrap
|
||||
);
|
||||
window.addEventListener('scroll', throttle(handleScroll, 250), {
|
||||
passive: true,
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
@ -60,3 +29,5 @@
|
|||
/>
|
||||
<link rel="stylesheet" href="https://a.pub.network/reuters-com/cls.css" />
|
||||
</svelte:head>
|
||||
|
||||
<OneTrust />
|
||||
|
|
|
|||
|
|
@ -1,46 +0,0 @@
|
|||
<script>
|
||||
import { Meta, Template, Story } from '@storybook/addon-svelte-csf';
|
||||
|
||||
// Don't lose the "?raw" in markdown imports!
|
||||
// @ts-ignore
|
||||
import componentDocs from './stories/docs/component.md?raw';
|
||||
|
||||
import AdScripts from './AdScripts.svelte';
|
||||
import AdSlot from './AdSlot.svelte';
|
||||
|
||||
import { withComponentDocs } from '$docs/utils/withParams.js';
|
||||
|
||||
const meta = {
|
||||
title: 'Components/AdSlot',
|
||||
component: AdSlot,
|
||||
...withComponentDocs(componentDocs),
|
||||
argTypes: {
|
||||
placementName: {
|
||||
control: 'select',
|
||||
options: ['reuters_desktop_native_1', 'reuters_desktop_canvas'],
|
||||
},
|
||||
dataFreestarAd: {
|
||||
control: 'select',
|
||||
options: ['__970x250'],
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<Meta {...meta} />
|
||||
|
||||
<Template let:args>
|
||||
<div>
|
||||
<AdScripts />
|
||||
<AdSlot {...args} />
|
||||
<AdSlot placementName="reuters_desktop_canvas" dataFreestarAd="__970x250" />
|
||||
</div>
|
||||
</Template>
|
||||
|
||||
<Story
|
||||
name="Default"
|
||||
args="{{
|
||||
placementName: 'reuters_desktop_native_1',
|
||||
dataFreestarAd: '__970x250',
|
||||
}}"
|
||||
/>
|
||||
|
|
@ -1,126 +1,29 @@
|
|||
<script lang="ts">
|
||||
/** ✏️ DOCUMENT your chart's props using TypeScript and JSDoc comments like below! */
|
||||
import type { PlacementName, AdType } from './@types/ads';
|
||||
import { onMount } from 'svelte';
|
||||
import { getRandomAdId } from './utils';
|
||||
|
||||
type PlacementName =
|
||||
// Disabling leaderboard for now...
|
||||
// | 'reuters_desktop_leaderboard_atf'
|
||||
// | 'reuters_mobile_leaderboard'
|
||||
| 'reuters_desktop_native_1'
|
||||
| 'reuters_mobile_mpu_1'
|
||||
| 'reuters_sponsorlogo'
|
||||
| 'reuters_desktop_canvas';
|
||||
export let placementName: PlacementName;
|
||||
export let adType: AdType;
|
||||
|
||||
/**
|
||||
* The unique placement name from FreeStar dashboard.
|
||||
* @required
|
||||
*/
|
||||
export let placementName: PlacementName = 'reuters_desktop_native_1';
|
||||
|
||||
/**
|
||||
* The unique slot Id from FreeStar dashboard.
|
||||
* @TODO Unclear at what level this bit of config is used with placements...
|
||||
*/
|
||||
export let dataFreestarAd: string = '__970x250';
|
||||
|
||||
/** Add an ID to target with SCSS. */
|
||||
export let id: string = '';
|
||||
|
||||
/** Add a class to target with SCSS. */
|
||||
let cls: string = 'my-12';
|
||||
export { cls as class };
|
||||
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
import Block from '../Block/Block.svelte';
|
||||
|
||||
const random4 = () =>
|
||||
Math.floor((1 + Math.random()) * 0x10000)
|
||||
.toString(16)
|
||||
.substring(1);
|
||||
|
||||
const randomAdId = 'ad-' + random4() + random4();
|
||||
|
||||
const getAdType = (placementName: PlacementName) => {
|
||||
switch (placementName) {
|
||||
// case 'reuters_desktop_leaderboard_atf':
|
||||
// case 'reuters_mobile_leaderboard':
|
||||
// return 'leaderboard';
|
||||
case 'reuters_sponsorlogo':
|
||||
return 'Sponsorlogo';
|
||||
case 'reuters_mobile_mpu_1':
|
||||
return 'mpu';
|
||||
default:
|
||||
return 'native';
|
||||
}
|
||||
};
|
||||
const adId = getRandomAdId();
|
||||
|
||||
onMount(() => {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const adstest = urlParams.get('adstest');
|
||||
window.graphicsAdQueue = window.graphicsAdQueue || [];
|
||||
window.graphicsAdQueue.push({
|
||||
placementName,
|
||||
slotId: randomAdId,
|
||||
type: getAdType(placementName),
|
||||
graphicId: window.location.pathname,
|
||||
adstest,
|
||||
slotId: adId,
|
||||
targeting: {
|
||||
div_id: adId,
|
||||
type: adType,
|
||||
},
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- @component `AdSlot` [Read the docs.](https://reuters-graphics.github.io/graphics-components/?path=/docs/components-AdSlot--default) -->
|
||||
<Block id="{id}" class="freestar-adslot {cls}">
|
||||
<div class="ad-block">
|
||||
<div class="ad-label">Advertisement · Scroll to continue</div>
|
||||
<div class="ad-container">
|
||||
<div class="ad-slot__inner">
|
||||
<div>
|
||||
<div
|
||||
data-freestar-ad="{dataFreestarAd || null}"
|
||||
id="{randomAdId}"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Block>
|
||||
|
||||
<style lang="scss">
|
||||
div.ad-block {
|
||||
border-bottom: 1px solid var(--theme-colour-brand-rules);
|
||||
border-top: 1px solid var(--theme-colour-brand-rules);
|
||||
div.ad-label {
|
||||
font-family: Knowledge, 'Source Sans Pro', Arial, Helvetica, sans-serif;
|
||||
font-size: 14px;
|
||||
margin: 6px 0;
|
||||
line-height: 1.333;
|
||||
color: var(--theme-colour-text-secondary);
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
div.ad-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 415px;
|
||||
@media (max-width: 767.9px) {
|
||||
min-height: 320px;
|
||||
}
|
||||
div.ad-slot__inner {
|
||||
margin: auto 0;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
flex: unset;
|
||||
& > div {
|
||||
display: block;
|
||||
div[data-freestar-ad] {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<div data-freestar-ad="{dataFreestarAd || null}" id="{adId}"></div>
|
||||
|
|
|
|||
29
src/components/AdSlot/InlineAd.stories.svelte
Normal file
29
src/components/AdSlot/InlineAd.stories.svelte
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<script>
|
||||
import { Meta, Template, Story } from '@storybook/addon-svelte-csf';
|
||||
|
||||
// @ts-ignore
|
||||
import componentDocs from './stories/docs/component.md?raw';
|
||||
|
||||
import AdScripts from './AdScripts.svelte';
|
||||
import InlineAd from './InlineAd.svelte';
|
||||
|
||||
import { withComponentDocs } from '$docs/utils/withParams.js';
|
||||
|
||||
const meta = {
|
||||
title: 'Components/InlineAd',
|
||||
component: InlineAd,
|
||||
...withComponentDocs(componentDocs),
|
||||
};
|
||||
</script>
|
||||
|
||||
<Meta title="Components/InlineAd" {...meta} />
|
||||
|
||||
<Template let:args>
|
||||
<div>
|
||||
<AdScripts />
|
||||
<InlineAd />
|
||||
<InlineAd />
|
||||
</div>
|
||||
</Template>
|
||||
|
||||
<Story name="Default" />
|
||||
69
src/components/AdSlot/InlineAd.svelte
Normal file
69
src/components/AdSlot/InlineAd.svelte
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
<script lang="ts">
|
||||
import Block from '../Block/Block.svelte';
|
||||
import { DesktopPlacementName } from './@types/ads';
|
||||
import ResponsiveAd from './ResponsiveAd.svelte';
|
||||
|
||||
/** Add an ID to target with SCSS. */
|
||||
export let id: string = '';
|
||||
|
||||
/** Add a class to target with SCSS. */
|
||||
let cls: string = 'my-12';
|
||||
export { cls as class };
|
||||
|
||||
const desktopPlacementName: DesktopPlacementName = 'reuters_desktop_native_1';
|
||||
</script>
|
||||
|
||||
<!-- @component `InlineAd` [Read the docs.](https://reuters-graphics.github.io/graphics-components/?path=/docs/components-InlineAd--default) -->
|
||||
<Block id="{id}" class="freestar-adslot {cls}">
|
||||
<div class="ad-block">
|
||||
<div class="ad-label">Advertisement · Scroll to continue</div>
|
||||
<div class="ad-container">
|
||||
<div class="ad-slot__inner">
|
||||
<div>
|
||||
<ResponsiveAd desktopPlacementName="{desktopPlacementName}" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Block>
|
||||
|
||||
<style lang="scss">
|
||||
div.ad-block {
|
||||
border-bottom: 1px solid var(--theme-colour-brand-rules);
|
||||
border-top: 1px solid var(--theme-colour-brand-rules);
|
||||
div.ad-label {
|
||||
font-family: Knowledge, 'Source Sans Pro', Arial, Helvetica, sans-serif;
|
||||
font-size: 14px;
|
||||
margin: 6px 0;
|
||||
line-height: 1.333;
|
||||
color: var(--theme-colour-text-secondary);
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
div.ad-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 415px;
|
||||
@media (max-width: 767.9px) {
|
||||
min-height: 320px;
|
||||
}
|
||||
div.ad-slot__inner {
|
||||
margin: auto 0;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
flex: unset;
|
||||
& > div {
|
||||
display: block;
|
||||
:global(div[data-freestar-ad]) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
39
src/components/AdSlot/OneTrust.svelte
Normal file
39
src/components/AdSlot/OneTrust.svelte
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<!-- This component manages the OneTrust prefs button, so it's not permanently fixed on page... -->
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import { throttle } from 'lodash-es';
|
||||
|
||||
let lastScroll = 0;
|
||||
let showManagePreferences = true;
|
||||
|
||||
const togglePrefs = (on = true) => {
|
||||
const btn = document.getElementById('ot-sdk-btn-floating');
|
||||
if (!btn) return;
|
||||
if (on) {
|
||||
showManagePreferences = true;
|
||||
btn.style.bottom = '';
|
||||
} else {
|
||||
showManagePreferences = false;
|
||||
btn.style.bottom = '-5rem';
|
||||
}
|
||||
};
|
||||
|
||||
const handleScroll = () => {
|
||||
if (lastScroll > window.scrollY) {
|
||||
if (!showManagePreferences) {
|
||||
togglePrefs(true);
|
||||
}
|
||||
} else {
|
||||
if (showManagePreferences && window.scrollY > 250) {
|
||||
togglePrefs(false);
|
||||
}
|
||||
}
|
||||
lastScroll = window.scrollY;
|
||||
};
|
||||
|
||||
onMount(() => {
|
||||
window.addEventListener('scroll', throttle(handleScroll, 250), {
|
||||
passive: true,
|
||||
});
|
||||
});
|
||||
</script>
|
||||
52
src/components/AdSlot/ResponsiveAd.svelte
Normal file
52
src/components/AdSlot/ResponsiveAd.svelte
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<script lang="ts">
|
||||
import type { DesktopPlacementName, PlacementName } from './@types/ads';
|
||||
import AdSlot from './AdSlot.svelte';
|
||||
|
||||
export let desktopPlacementName: DesktopPlacementName;
|
||||
export let mobileBreakpoint = 1024;
|
||||
|
||||
let windowWidth: number;
|
||||
|
||||
const getMobilePlacementName = (
|
||||
desktopPlacementName: DesktopPlacementName
|
||||
) => {
|
||||
switch (desktopPlacementName) {
|
||||
case 'reuters_desktop_leaderboard_atf':
|
||||
return 'reuters_mobile_leaderboard' as const;
|
||||
case 'reuters_sponsorlogo':
|
||||
return 'reuters_sponsorlogo' as const;
|
||||
default:
|
||||
return 'reuters_mobile_mpu_1' as const;
|
||||
}
|
||||
};
|
||||
|
||||
const getAdType = (placementName: PlacementName) => {
|
||||
switch (placementName) {
|
||||
case 'reuters_desktop_leaderboard_atf':
|
||||
case 'reuters_mobile_leaderboard':
|
||||
return 'leaderboard' as const;
|
||||
case 'reuters_sponsorlogo':
|
||||
return 'sponsorlogo' as const;
|
||||
case 'reuters_mobile_mpu_1':
|
||||
return 'mpu' as const;
|
||||
case 'reuters_billboard_desktop':
|
||||
return 'billboard' as const;
|
||||
default:
|
||||
return 'native' as const;
|
||||
}
|
||||
};
|
||||
|
||||
$: placementName =
|
||||
windowWidth && windowWidth < mobileBreakpoint
|
||||
? getMobilePlacementName(desktopPlacementName)
|
||||
: desktopPlacementName;
|
||||
$: adType = getAdType(placementName);
|
||||
</script>
|
||||
|
||||
<svelte:window bind:innerWidth="{windowWidth}" />
|
||||
|
||||
{#if windowWidth}
|
||||
{#key placementName}
|
||||
<AdSlot placementName="{placementName}" adType="{adType}" />
|
||||
{/key}
|
||||
{/if}
|
||||
|
|
@ -46,19 +46,15 @@ export const loadBootstrap = () => {
|
|||
loadScript('https://a.pub.network/reuters-com/pubfig.min.js');
|
||||
|
||||
// Set GAM
|
||||
(<any>window).googletag = (<any>window).googletag || { cmd: [] };
|
||||
(<any>window).googletag.cmd.push(() => {
|
||||
(<any>window).googletag.pubads().enableSingleRequest();
|
||||
(<any>window).googletag.pubads().enableAsyncRendering();
|
||||
(<any>window).googletag.pubads().collapseEmptyDivs(true);
|
||||
|
||||
// Global Ads test targeting
|
||||
const adstest = new URL(document.location.href).searchParams.get('adstest');
|
||||
if (adstest) {
|
||||
(<any>window).googletag.pubads().setTargeting('adstest', adstest);
|
||||
}
|
||||
|
||||
(<any>window).googletag.pubads().setTargeting('template', 'graphics');
|
||||
window.googletag = (<any>window).googletag || { cmd: [] };
|
||||
window.googletag.cmd.push(() => {
|
||||
window.googletag.pubads().enableSingleRequest();
|
||||
/**
|
||||
* @TODO Property 'enableAsyncRendering' does not exist on type 'PubAdsService'.
|
||||
*/
|
||||
// @ts-ignore
|
||||
window.googletag.pubads().enableAsyncRendering();
|
||||
window.googletag.pubads().collapseEmptyDivs(true);
|
||||
});
|
||||
|
||||
if (!Array.isArray((<any>window).graphicsAdQueue)) {
|
||||
|
|
@ -66,11 +62,24 @@ export const loadBootstrap = () => {
|
|||
}
|
||||
|
||||
freestar.queue.push(function() {
|
||||
freestar.newAdSlots((<any>window).graphicsAdQueue || [], 'foobar');
|
||||
freestar.newAdSlots((<any>window).graphicsAdQueue || [], freestar.config.channel);
|
||||
});
|
||||
|
||||
// Set page-level key-values
|
||||
// cf: https://help.freestar.com/help/using-key-values
|
||||
freestar.queue.push(function() {
|
||||
(<any>window).googletag.pubads().set('page_url', 'https://www.reuters.com/'); // This line should only be used for testing
|
||||
// Global Ads test targeting
|
||||
const adstest = new URL(document.location.href).searchParams.get('adstest');
|
||||
if (adstest) {
|
||||
window.googletag.pubads().setTargeting('adstest', adstest);
|
||||
}
|
||||
|
||||
// Use the URL path to create a unique ID for the page.
|
||||
const graphicId = window.location.pathname
|
||||
.replace(/^\/(.*)\/$/, '$1')
|
||||
.replaceAll('/', '-');
|
||||
window.googletag.pubads().setTargeting('template', 'graphics');
|
||||
window.googletag.pubads().setTargeting('graphicId', graphicId);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
|
|
|||
6
src/components/AdSlot/utils.ts
Normal file
6
src/components/AdSlot/utils.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
const random4 = () =>
|
||||
Math.floor((1 + Math.random()) * 0x10000)
|
||||
.toString(16)
|
||||
.substring(1);
|
||||
|
||||
export const getRandomAdId = () => 'ad-' + random4() + random4();
|
||||
|
|
@ -9,7 +9,7 @@ export {
|
|||
} from './components/Analytics/Analytics.svelte';
|
||||
export { default as Article } from './components/Article/Article.svelte';
|
||||
export { default as AdScripts } from './components/AdSlot/AdScripts.svelte';
|
||||
export { default as AdSlot } from './components/AdSlot/AdSlot.svelte';
|
||||
export { default as InlineAd } from './components/AdSlot/InlineAd.svelte';
|
||||
export { default as BeforeAfter } from './components/BeforeAfter/BeforeAfter.svelte';
|
||||
export { default as Block } from './components/Block/Block.svelte';
|
||||
export { default as BodyText } from './components/BodyText/BodyText.svelte';
|
||||
|
|
|
|||
|
|
@ -2993,6 +2993,11 @@
|
|||
resolved "https://registry.npmjs.org/@types/find-cache-dir/-/find-cache-dir-3.2.1.tgz"
|
||||
integrity sha512-frsJrz2t/CeGifcu/6uRo4b+SzAwT4NYCVPu1GN8IB9XTzrpPkGuV0tmh9mN+/L0PklAlsC3u5Fxt0ju00LXIw==
|
||||
|
||||
"@types/google-publisher-tag@^1.20240219.0":
|
||||
version "1.20240219.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/google-publisher-tag/-/google-publisher-tag-1.20240219.0.tgz#4b883f033b923bf161f61942adb58c58a7dbea16"
|
||||
integrity sha512-CvXeyjN9deEo6+nAqgHsGItPhWKnqkeLOqGlZmrb7inO8KUUQTmk2xfVqUnwIi6YKfBrpV4ZODd1TkgnXaIAjw==
|
||||
|
||||
"@types/graceful-fs@^4.1.3":
|
||||
version "4.1.6"
|
||||
resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz"
|
||||
|
|
|
|||
Loading…
Reference in a new issue