diff options
Diffstat (limited to 'web/src/adSlot.js')
| -rw-r--r-- | web/src/adSlot.js | 53 |
1 files changed, 51 insertions, 2 deletions
diff --git a/web/src/adSlot.js b/web/src/adSlot.js index 4b8ce2e..6dfb5b5 100644 --- a/web/src/adSlot.js +++ b/web/src/adSlot.js @@ -20,8 +20,13 @@ import { getUser, onAuthChange } from './auth.js'; // consent requirements with it. There is no consent mechanism here. // // Shown to signed-out visitors and to signed-in accounts without the -// supporter flag. Never shown on the typing screen: interrupting somebody -// mid-test is the one placement that would cost more than it earns. +// supporter flag. Never shown while typing: interrupting somebody mid-test is +// the one placement that would cost more than it earns. +// +// The slot sits across the top of the page, where a site's navigation bar +// usually goes, and the header moves down to make room rather than being +// covered. Screens that must not carry it call setAdBannerScreen with their +// own name. const SIZES = { // Roughly a leaderboard unit, and a mobile banner below the breakpoint. @@ -58,3 +63,47 @@ export function renderAdSlot(root, { size = 'banner', label = 'Advertisement' } wrap.remove(); }; } + + +// Screens the banner stays off. Typing and passive reading are both somebody +// working through a text, and the race lobby leads straight into typing. +const HIDDEN_ON = new Set(['typing', 'passive', 'multiplayer']); + +/// Mounts the top banner once, outside the screen root so that redrawing a +/// screen does not reload it. Returns a function that takes the current +/// screen name. +export function mountTopAdBanner() { + const bar = document.createElement('div'); + bar.className = 'ad-banner-top'; + document.body.insertBefore(bar, document.body.firstChild); + + const inner = document.createElement('div'); + inner.className = 'ad-banner-inner'; + bar.appendChild(inner); + const cleanupSlot = renderAdSlot(inner); + + let screenName = 'menu'; + + function paint() { + const show = shouldShowAds() && !HIDDEN_ON.has(screenName); + bar.hidden = !show; + // The wordmark and the top rail are fixed to the top of the viewport + // and the content column is offset from it, so all three have to know + // the banner's height or the banner would sit on top of them. + document.documentElement.style.setProperty( + '--ad-banner-h', show ? 'var(--ad-banner-height)' : '0px'); + } + + paint(); + const unsubscribe = onAuthChange(paint); + + return { + setScreen(name) { screenName = name; paint(); }, + cleanup() { + unsubscribe(); + cleanupSlot(); + bar.remove(); + document.documentElement.style.removeProperty('--ad-banner-h'); + }, + }; +} |