mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 09:30:45 +00:00
Refactor home page ads into a single file, add corner video ad (#3601)
## Description: <img width="3608" height="1848" alt="image" src="https://github.com/user-attachments/assets/86074bff-e648-4db4-a3e9-08d49e433df0" /> ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: evan
This commit is contained in:
+1
-1
@@ -174,7 +174,7 @@
|
||||
class="fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 z-99999"
|
||||
></div>
|
||||
|
||||
<gutter-ads></gutter-ads>
|
||||
<homepage-promos></homepage-promos>
|
||||
|
||||
<!-- Main container with responsive padding -->
|
||||
<main-layout class="contents">
|
||||
|
||||
@@ -1,162 +0,0 @@
|
||||
import { LitElement, css, html } from "lit";
|
||||
import { customElement, state } from "lit/decorators.js";
|
||||
import { FOOTER_AD_MIN_HEIGHT } from "./components/HomeFooterAd";
|
||||
|
||||
@customElement("gutter-ads")
|
||||
export class GutterAds extends LitElement {
|
||||
@state()
|
||||
private isVisible: boolean = false;
|
||||
|
||||
@state()
|
||||
private adLoaded: boolean = false;
|
||||
|
||||
@state()
|
||||
private hasFooterAd: boolean = false;
|
||||
|
||||
private onResize = () => {
|
||||
const isDesktop = window.innerWidth >= 640;
|
||||
this.hasFooterAd = isDesktop && window.innerHeight >= FOOTER_AD_MIN_HEIGHT;
|
||||
};
|
||||
|
||||
private leftAdType: string = "standard_iab_left2";
|
||||
private rightAdType: string = "standard_iab_rght1";
|
||||
private leftContainerId: string = "gutter-ad-container-left";
|
||||
private rightContainerId: string = "gutter-ad-container-right";
|
||||
|
||||
// Override createRenderRoot to disable shadow DOM
|
||||
createRenderRoot() {
|
||||
return this;
|
||||
}
|
||||
|
||||
static styles = css``;
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this.onResize();
|
||||
window.addEventListener("resize", this.onResize);
|
||||
document.addEventListener("userMeResponse", () => {
|
||||
if (window.adsEnabled) {
|
||||
console.log("showing gutter ads");
|
||||
this.show();
|
||||
} else {
|
||||
console.log("not showing gutter ads");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Called after the component's DOM is first rendered
|
||||
firstUpdated() {
|
||||
// DOM is guaranteed to be available here
|
||||
console.log("GutterAdModal DOM is ready");
|
||||
}
|
||||
|
||||
public show(): void {
|
||||
this.isVisible = true;
|
||||
this.requestUpdate();
|
||||
|
||||
// Wait for the update to complete, then load ads
|
||||
this.updateComplete.then(() => {
|
||||
this.loadAds();
|
||||
});
|
||||
}
|
||||
|
||||
public close(): void {
|
||||
try {
|
||||
window.ramp.destroyUnits(this.leftAdType);
|
||||
window.ramp.destroyUnits(this.rightAdType);
|
||||
console.log("successfully destroyed gutter ads");
|
||||
} catch (e) {
|
||||
console.error("error destroying gutter ads", e);
|
||||
}
|
||||
}
|
||||
|
||||
private loadAds(): void {
|
||||
console.log("loading ramp ads");
|
||||
// Ensure the container elements exist before loading ads
|
||||
const leftContainer = this.querySelector(`#${this.leftContainerId}`);
|
||||
const rightContainer = this.querySelector(`#${this.rightContainerId}`);
|
||||
|
||||
if (!leftContainer || !rightContainer) {
|
||||
console.warn("Ad containers not found in DOM");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!window.ramp) {
|
||||
console.warn("Playwire RAMP not available");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.adLoaded) {
|
||||
console.log("Ads already loaded, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
window.ramp.que.push(() => {
|
||||
try {
|
||||
window.ramp.spaAddAds([
|
||||
{
|
||||
type: this.leftAdType,
|
||||
selectorId: this.leftContainerId,
|
||||
},
|
||||
{
|
||||
type: this.rightAdType,
|
||||
selectorId: this.rightContainerId,
|
||||
},
|
||||
]);
|
||||
this.adLoaded = true;
|
||||
console.log(
|
||||
"Playwire ads loaded:",
|
||||
this.leftAdType,
|
||||
this.rightAdType,
|
||||
);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Failed to load Playwire ads:", error);
|
||||
}
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
window.removeEventListener("resize", this.onResize);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.isVisible) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
return html`
|
||||
<!-- Left Gutter Ad -->
|
||||
<div
|
||||
class="hidden xl:flex fixed transform -translate-y-1/2 w-[160px] min-h-[600px] z-40 pointer-events-auto items-center justify-center xl:[--half-content:10.5cm] 2xl:[--half-content:12.5cm]"
|
||||
style="left: calc(50% - var(--half-content) - 208px); top: calc(50% + 10px${this
|
||||
.hasFooterAd
|
||||
? " - 1.2cm"
|
||||
: ""});"
|
||||
>
|
||||
<div
|
||||
id="${this.leftContainerId}"
|
||||
class="w-full h-full flex items-center justify-center p-2"
|
||||
></div>
|
||||
</div>
|
||||
|
||||
<!-- Right Gutter Ad -->
|
||||
<div
|
||||
class="hidden xl:flex fixed transform -translate-y-1/2 w-[160px] min-h-[600px] z-40 pointer-events-auto items-center justify-center xl:[--half-content:10.5cm] 2xl:[--half-content:12.5cm]"
|
||||
style="left: calc(50% + var(--half-content) + 48px); top: calc(50% + 10px${this
|
||||
.hasFooterAd
|
||||
? " - 1.2cm"
|
||||
: ""});"
|
||||
>
|
||||
<div
|
||||
id="${this.rightContainerId}"
|
||||
class="w-full h-full flex items-center justify-center p-2"
|
||||
></div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
import { LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, state } from "lit/decorators.js";
|
||||
|
||||
export const FOOTER_AD_MIN_HEIGHT = 880;
|
||||
|
||||
const FOOTER_AD_TYPE = "standard_iab_head2";
|
||||
const FOOTER_AD_CONTAINER_ID = "home-footer-ad-container";
|
||||
|
||||
// ─── Gutter Ads ──────────────────────────────────────────────────────────────
|
||||
|
||||
@customElement("homepage-promos")
|
||||
export class HomepagePromos extends LitElement {
|
||||
@state() private isVisible: boolean = false;
|
||||
@state() private adLoaded: boolean = false;
|
||||
private cornerAdLoaded: boolean = false;
|
||||
@state() private hasFooterAd: boolean = false;
|
||||
|
||||
private onResize = () => {
|
||||
const isDesktop = window.innerWidth >= 640;
|
||||
this.hasFooterAd = isDesktop && window.innerHeight >= FOOTER_AD_MIN_HEIGHT;
|
||||
};
|
||||
|
||||
private onUserMeResponse = () => {
|
||||
if (window.adsEnabled) {
|
||||
console.log("showing homepage ads");
|
||||
this.show();
|
||||
this.loadCornerAdVideo();
|
||||
} else {
|
||||
console.log("not showing homepage ads");
|
||||
}
|
||||
};
|
||||
|
||||
private leftAdType: string = "standard_iab_left2";
|
||||
private rightAdType: string = "standard_iab_rght1";
|
||||
private leftContainerId: string = "gutter-ad-container-left";
|
||||
private rightContainerId: string = "gutter-ad-container-right";
|
||||
|
||||
createRenderRoot() {
|
||||
return this;
|
||||
}
|
||||
|
||||
static styles = css``;
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this.onResize();
|
||||
window.addEventListener("resize", this.onResize);
|
||||
document.addEventListener("userMeResponse", this.onUserMeResponse);
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
window.removeEventListener("resize", this.onResize);
|
||||
document.removeEventListener("userMeResponse", this.onUserMeResponse);
|
||||
}
|
||||
|
||||
public show(): void {
|
||||
this.isVisible = true;
|
||||
this.requestUpdate();
|
||||
this.updateComplete.then(() => {
|
||||
this.loadGutterAds();
|
||||
});
|
||||
}
|
||||
|
||||
public close(): void {
|
||||
try {
|
||||
// Keep corner video ad alive.
|
||||
window.ramp.destroyUnits(this.leftAdType);
|
||||
window.ramp.destroyUnits(this.rightAdType);
|
||||
console.log("successfully destroyed gutter ads");
|
||||
} catch (e) {
|
||||
console.error("error destroying gutter ads", e);
|
||||
}
|
||||
}
|
||||
|
||||
private loadGutterAds(): void {
|
||||
console.log("loading ramp gutter ads");
|
||||
const leftContainer = this.querySelector(`#${this.leftContainerId}`);
|
||||
const rightContainer = this.querySelector(`#${this.rightContainerId}`);
|
||||
|
||||
if (!leftContainer || !rightContainer) {
|
||||
console.warn("Ad containers not found in DOM");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!window.ramp) {
|
||||
console.warn("Playwire RAMP not available");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.adLoaded) {
|
||||
console.log("Ads already loaded, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
window.ramp.que.push(() => {
|
||||
try {
|
||||
window.ramp.spaAddAds([
|
||||
{ type: this.leftAdType, selectorId: this.leftContainerId },
|
||||
{ type: this.rightAdType, selectorId: this.rightContainerId },
|
||||
]);
|
||||
this.adLoaded = true;
|
||||
console.log("Gutter ads loaded:", this.leftAdType, this.rightAdType);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Failed to load gutter ads:", error);
|
||||
}
|
||||
}
|
||||
|
||||
private loadCornerAdVideo(): void {
|
||||
if (this.cornerAdLoaded) return;
|
||||
if (window.innerWidth < 1280) return;
|
||||
if (!window.ramp) {
|
||||
console.warn("Playwire RAMP not available for corner_ad_video");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
window.ramp.que.push(() => {
|
||||
try {
|
||||
window.ramp
|
||||
.addUnits([{ type: "corner_ad_video" }])
|
||||
.then(() => {
|
||||
this.cornerAdLoaded = true;
|
||||
window.ramp.displayUnits();
|
||||
console.log("corner_ad_video loaded");
|
||||
})
|
||||
.catch((e: unknown) => {
|
||||
console.error("Failed to display corner_ad_video:", e);
|
||||
});
|
||||
} catch (e) {
|
||||
console.error("Failed to add corner_ad_video:", e);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Failed to load corner_ad_video:", error);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.isVisible) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
return html`
|
||||
<!-- Left Gutter Ad -->
|
||||
<div
|
||||
class="hidden xl:flex fixed transform -translate-y-1/2 w-[160px] min-h-[600px] z-40 pointer-events-auto items-center justify-center xl:[--half-content:10.5cm] 2xl:[--half-content:12.5cm]"
|
||||
style="left: calc(50% - var(--half-content) - 208px); top: calc(50% + 10px${this
|
||||
.hasFooterAd
|
||||
? " - 1.2cm"
|
||||
: ""});"
|
||||
>
|
||||
<div
|
||||
id="${this.leftContainerId}"
|
||||
class="w-full h-full flex items-center justify-center p-2"
|
||||
></div>
|
||||
</div>
|
||||
|
||||
<!-- Right Gutter Ad -->
|
||||
<div
|
||||
class="hidden xl:flex fixed transform -translate-y-1/2 w-[160px] min-h-[600px] z-40 pointer-events-auto items-center justify-center xl:[--half-content:10.5cm] 2xl:[--half-content:12.5cm]"
|
||||
style="left: calc(50% + var(--half-content) + 48px); top: calc(50% + 10px${this
|
||||
.hasFooterAd
|
||||
? " - 1.2cm"
|
||||
: ""});"
|
||||
>
|
||||
<div
|
||||
id="${this.rightContainerId}"
|
||||
class="w-full h-full flex items-center justify-center p-2"
|
||||
></div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Footer Ad ───────────────────────────────────────────────────────────────
|
||||
|
||||
@customElement("home-footer-ad")
|
||||
export class HomeFooterAd extends LitElement {
|
||||
@state() private shouldShow: boolean = false;
|
||||
|
||||
createRenderRoot() {
|
||||
return this;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this.style.display = "contents";
|
||||
document.addEventListener("userMeResponse", this.onUserMeResponse);
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
document.removeEventListener("userMeResponse", this.onUserMeResponse);
|
||||
this.destroyAd();
|
||||
}
|
||||
|
||||
private onUserMeResponse = () => {
|
||||
const isDesktop = window.innerWidth >= 640;
|
||||
if (
|
||||
!window.adsEnabled ||
|
||||
(isDesktop && window.innerHeight < FOOTER_AD_MIN_HEIGHT)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
this.shouldShow = true;
|
||||
this.updateComplete.then(() => {
|
||||
this.loadAd();
|
||||
});
|
||||
};
|
||||
|
||||
private loadAd(): void {
|
||||
if (!window.ramp) {
|
||||
console.warn("Playwire RAMP not available for footer ad");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
window.ramp.que.push(() => {
|
||||
try {
|
||||
window.ramp.spaAddAds([
|
||||
{ type: FOOTER_AD_TYPE, selectorId: FOOTER_AD_CONTAINER_ID },
|
||||
]);
|
||||
console.log("Footer ad loaded:", FOOTER_AD_TYPE);
|
||||
} catch (e) {
|
||||
console.error("Failed to add footer ad:", e);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Failed to load footer ad:", error);
|
||||
}
|
||||
}
|
||||
|
||||
private destroyAd(): void {
|
||||
try {
|
||||
window.ramp.destroyUnits(FOOTER_AD_TYPE);
|
||||
console.log("successfully destroyed footer ad");
|
||||
} catch (e) {
|
||||
console.error("error destroying footer ad", e);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.shouldShow) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
return html`
|
||||
<div
|
||||
id="${FOOTER_AD_CONTAINER_ID}"
|
||||
class="flex justify-center items-center w-full pointer-events-auto [&_*]:!m-0 [&_*]:!p-0"
|
||||
style="margin: 0; padding: 0; line-height: 0;"
|
||||
></div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
+5
-8
@@ -27,8 +27,8 @@ import "./GameModeSelector";
|
||||
import { GameModeSelector } from "./GameModeSelector";
|
||||
import { GameStartingModal } from "./GameStartingModal";
|
||||
import "./GoogleAdElement";
|
||||
import { GutterAds } from "./GutterAds";
|
||||
import { HelpModal } from "./HelpModal";
|
||||
import { HomepagePromos } from "./HomepagePromos";
|
||||
import { HostLobbyModal as HostPrivateLobbyModal } from "./HostLobbyModal";
|
||||
import { JoinLobbyModal } from "./JoinLobbyModal";
|
||||
import "./LangSelector";
|
||||
@@ -60,7 +60,6 @@ import {
|
||||
} from "./Utils";
|
||||
import "./components/DesktopNavBar";
|
||||
import "./components/Footer";
|
||||
import "./components/HomeFooterAd";
|
||||
import "./components/MainLayout";
|
||||
import "./components/MobileNavBar";
|
||||
import "./components/PlayPage";
|
||||
@@ -245,7 +244,6 @@ class Client {
|
||||
private tokenLoginModal: TokenLoginModal;
|
||||
private matchmakingModal: MatchmakingModal;
|
||||
|
||||
private gutterAds: GutterAds;
|
||||
private turnstileTokenPromise: Promise<{
|
||||
token: string;
|
||||
createdAt: number;
|
||||
@@ -305,10 +303,9 @@ class Client {
|
||||
}
|
||||
});
|
||||
|
||||
const gutterAds = document.querySelector("gutter-ads");
|
||||
if (!(gutterAds instanceof GutterAds))
|
||||
throw new Error("Missing gutter-ads");
|
||||
this.gutterAds = gutterAds;
|
||||
const gutterAds = document.querySelector("homepage-promos");
|
||||
if (!(gutterAds instanceof HomepagePromos))
|
||||
throw new Error("Missing homepage-promos");
|
||||
|
||||
document.addEventListener("join-lobby", this.handleJoinLobby.bind(this));
|
||||
document.addEventListener("leave-lobby", this.handleLeaveLobby.bind(this));
|
||||
@@ -774,7 +771,7 @@ class Client {
|
||||
"token-login",
|
||||
"matchmaking-modal",
|
||||
"lang-selector",
|
||||
"gutter-ads",
|
||||
"homepage-promos",
|
||||
].forEach((tag) => {
|
||||
const modal = document.querySelector(tag) as HTMLElement & {
|
||||
close?: () => void;
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
import { LitElement, html, nothing } from "lit";
|
||||
import { customElement, state } from "lit/decorators.js";
|
||||
|
||||
export const FOOTER_AD_MIN_HEIGHT = 880;
|
||||
const FOOTER_AD_TYPE = "standard_iab_head2";
|
||||
const FOOTER_AD_CONTAINER_ID = "home-footer-ad-container";
|
||||
|
||||
@customElement("home-footer-ad")
|
||||
export class HomeFooterAd extends LitElement {
|
||||
@state() private shouldShow: boolean = false;
|
||||
|
||||
createRenderRoot() {
|
||||
return this;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this.style.display = "contents";
|
||||
document.addEventListener("userMeResponse", this.onUserMeResponse);
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
document.removeEventListener("userMeResponse", this.onUserMeResponse);
|
||||
this.destroyAd();
|
||||
}
|
||||
|
||||
private onUserMeResponse = () => {
|
||||
const isDesktop = window.innerWidth >= 640;
|
||||
if (
|
||||
!window.adsEnabled ||
|
||||
(isDesktop && window.innerHeight < FOOTER_AD_MIN_HEIGHT)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
this.shouldShow = true;
|
||||
this.updateComplete.then(() => {
|
||||
this.loadAd();
|
||||
});
|
||||
};
|
||||
|
||||
private loadAd(): void {
|
||||
if (!window.ramp) {
|
||||
console.warn("Playwire RAMP not available for footer ad");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
window.ramp.que.push(() => {
|
||||
try {
|
||||
window.ramp.spaAddAds([
|
||||
{ type: FOOTER_AD_TYPE, selectorId: FOOTER_AD_CONTAINER_ID },
|
||||
]);
|
||||
console.log("Footer ad loaded:", FOOTER_AD_TYPE);
|
||||
} catch (e) {
|
||||
console.error("Failed to add footer ad:", e);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Failed to load footer ad:", error);
|
||||
}
|
||||
}
|
||||
|
||||
private destroyAd(): void {
|
||||
try {
|
||||
window.ramp.destroyUnits(FOOTER_AD_TYPE);
|
||||
console.log("successfully destroyed footer ad");
|
||||
} catch (e) {
|
||||
console.error("error destroying footer ad", e);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.shouldShow) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
return html`
|
||||
<div
|
||||
id="${FOOTER_AD_CONTAINER_ID}"
|
||||
class="flex justify-center items-center w-full pointer-events-auto [&_*]:!m-0 [&_*]:!p-0"
|
||||
style="margin: 0; padding: 0; line-height: 0;"
|
||||
></div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user