Files
OpenFrontIO/src/client/GoogleAdElement.ts
T
Skigim f7598369ed refactor: consolidate platform detection across client components (#3325)
## Description:

This PR consolidates ad hoc platform/environment/viewport detection into
a single shared utility. It is scoped to this refactor only, and serves
as groundwork for the mobile-focused feature work planned for the v31
milestone.

### What changed
- Introduced a shared `Platform` utility centralising:
  - OS detection (with `userAgentData` + UA fallback)
  - Electron environment detection
- Viewport breakpoint helpers (`isMobileWidth`, `isTabletWidth`,
`isDesktopWidth`)
- Replaced duplicated inline checks across client files with the shared
API.
- Normalised Mac detection to derive from the consolidated OS logic
rather than a separate regex.

### Why
- Multiple client files each independently ran `navigator.userAgent`
regexes or copy-pasted `isElectron` logic — this unifies all of that.
- Puts a stable, tested abstraction in place before v31 mobile work
lands, so mobile feature branches have a consistent surface to build
against.

## Please complete the following:

- [x] I have added screenshots for all UI updates (N/A: refactor only,
no visible UI changes)
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file (N/A: no new user-facing strings)
- [x] I have added relevant tests to the test directory (N/A: refactor
only)
- [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:

skigim
2026-03-02 10:12:48 -08:00

70 lines
1.9 KiB
TypeScript

import { LitElement, html } from "lit";
import { customElement, property } from "lit/decorators.js";
import { Platform } from "./Platform";
declare global {
interface Window {
adsbygoogle: unknown[];
}
}
/**
* Google AdSense integration component
*
* This component creates a configurable container for Google AdSense ads
* and properly initializes them after the component is rendered.
*/
@customElement("google-ad")
export class GoogleAdElement extends LitElement {
// Configurable properties
@property({ type: String }) adClient = "ca-pub-7035513310742290";
@property({ type: String }) adSlot = "5220834834";
@property({ type: String }) adFormat = "auto";
@property({ type: Boolean }) fullWidthResponsive = true;
@property({ type: String }) adTest = "off"; // "on" for testing, remove or set to "off" for production
// Disable shadow DOM so AdSense can access the elements
createRenderRoot() {
return this;
}
render() {
if (Platform.isElectron) {
return html``;
}
return html`
<div class="mt-4 rounded-lg p-2 w-full overflow-hidden">
<ins
class="adsbygoogle block"
data-ad-client="${this.adClient}"
data-ad-slot="${this.adSlot}"
data-ad-format="${this.adFormat}"
data-full-width-responsive="${this.fullWidthResponsive}"
data-adtest="${this.adTest}"
></ins>
</div>
`;
}
connectedCallback() {
super.connectedCallback();
if (Platform.isElectron) {
return;
}
// Wait for the component to be fully rendered
setTimeout(() => {
try {
// Initialize this specific ad
(window.adsbygoogle = window.adsbygoogle || []).push({});
console.log("Ad initialized for slot:", this.adSlot);
} catch (e) {
console.error("AdSense initialization error for slot:", this.adSlot, e);
}
}, 100);
}
}
export default GoogleAdElement;