Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"devDependencies": {
"@interledger/open-payments": "^7.1.3",
"@shared/types": "workspace:^",
"@shared/utils": "workspace:^",
"publisher-tools-api": "workspace:^",
"typescript": "^5.9.3",
"vite": "^5.4.20"
Expand Down
11 changes: 7 additions & 4 deletions components/src/banner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ import type {
BannerPositionKey,
BannerFontSize,
} from '@shared/types'
import { getExtensionHref } from '@shared/utils/extension'
import bannerStyles from './banner.css?raw'
import { getWebMonetizationLinkHref, applyFontFamily } from './utils.js'
import { applyFontFamily } from './utils.js'

const DEFAULT_BANNER_TITLE = 'How to support?'
const DEFAULT_BANNER_DESCRIPTION =
Expand Down Expand Up @@ -136,8 +137,6 @@ export class Banner extends LitElement {
? html`<p class="banner-description">${description}</p>`
: null

const extensionLink = getWebMonetizationLinkHref(navigator.userAgent)

return html`
<div class="banner ${this.animationClass}">
${thumbnail}
Expand All @@ -147,7 +146,7 @@ export class Banner extends LitElement {
${descriptionElement}
<a
class="banner-link"
href="${extensionLink}"
href="${this.extensionUrl}"
target="_blank"
rel="noopener noreferrer"
@click=${this.handleLinkClick}
Expand All @@ -174,6 +173,10 @@ export class Banner extends LitElement {
</div>
`
}

get extensionUrl(): string {
return getExtensionHref('banner')
}
}

interface BannerState {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@ import iconWallet from '@c/assets/icon_wallet.svg?raw'
import iconClose from '@c/assets/icon_x_close.svg?raw'
import { PoweredByInterledger } from '@c/shared/powered-by-interledger'
import { WebMonetizationHeader } from '@c/shared/web-monetization-header'
import { getWebMonetizationLinkHref } from '@c/utils'
import { getExtensionHref } from '@shared/utils/extension'
import styles from './install-required.css?raw'
import styleTokens from '../../vars.css?raw'

const TITLE = 'Web Monetization'
const HEADER_TEXT = `Get the Web Monetization Extension to be able to support us`
const STEP_1 = `You'll need a Web Monetization compatible wallet to use with the extension.`
const STEP_2 = `Install the Web Monetization extension from your browser's web store. This includes getting and/or connecting to your wallet.`
Expand All @@ -37,7 +36,7 @@ export class InstallRequired extends LitElement {
render() {
return html`
<div class="container">
<wm-header title="${TITLE}" size="large"></wm-header>
<wm-header size="large"></wm-header>

<h2>${HEADER_TEXT}</h2>

Expand Down Expand Up @@ -91,10 +90,7 @@ export class InstallRequired extends LitElement {
}

get extensionUrl(): string {
const url = new URL(getWebMonetizationLinkHref(navigator.userAgent))
url.searchParams.set('utm_source', window.location.origin)
url.searchParams.set('utm_medium', 'offerwall-embed')
return url.href
return getExtensionHref('offerwall')
}

#onExtensionLinkClick = (ev: MouseEvent) => {
Expand Down
20 changes: 0 additions & 20 deletions components/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,23 +55,3 @@ function getCustomFontData(fontName: FontFamilyKey, baseUrl: string) {
}
}
}

/**
* Gets the appropriate Web Monetization extension download link based on the user agent
* @param userAgent - The user agent string from navigator.userAgent
* @returns The download URL for the Web Monetization extension
*/
export const getWebMonetizationLinkHref = (userAgent: string): string => {
if (userAgent.includes('Firefox')) {
return 'https://addons.mozilla.org/en-US/firefox/addon/web-monetization-extension/'
} else if (
userAgent.includes('Chrome') &&
!userAgent.includes('Edg') &&
!userAgent.includes('OPR')
) {
return 'https://chromewebstore.google.com/detail/web-monetization/oiabcfomehhigdepbbclppomkhlknpii'
} else if (userAgent.includes('Edg')) {
return 'https://microsoftedge.microsoft.com/addons/detail/web-monetization/imjgemgmeoioefpmfefmffbboogighjl'
}
return 'https://webmonetization.org/'
}
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions shared/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,3 +288,11 @@ export const FONT_FAMILY_OPTIONS = [
] as const

export type FontFamilyKey = (typeof FONT_FAMILY_OPTIONS)[number]

export type UtmParams = {
utm_source: string
utm_medium: string
utm_campaign?: string
utm_content?: string
utm_term?: string
}
80 changes: 80 additions & 0 deletions shared/utils/extension.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import type { Tool, UtmParams } from '@shared/types'
import { urlWithParams } from './index'

type BrowserId = NonNullable<ReturnType<typeof getBrowserSupportForExtension>>

const URL_MAP: Record<BrowserId, string> = {
chrome: `https://chromewebstore.google.com/detail/web-monetization/oiabcfomehhigdepbbclppomkhlknpii`,
chromium: `https://chromewebstore.google.com/detail/web-monetization/oiabcfomehhigdepbbclppomkhlknpii`,
edge: `https://microsoftedge.microsoft.com/addons/detail/web-monetization/imjgemgmeoioefpmfefmffbboogighjl`,
firefox: `https://addons.mozilla.org/en-US/firefox/addon/web-monetization-extension/`,
safari: `https://apps.apple.com/app/web-monetization/id6754325288`,
}

export function getBrowserSupportForExtension(ua: string, vendor = '') {
const isMobile =
/Mobi|Android|iPhone|iPad|iPod/i.test(ua) ||
(navigator.maxTouchPoints > 0 && /Macintosh/.test(ua))
const isMacOS = /Macintosh/i.test(ua) && !isMobile

// Firefox (Desktop & Android supported, iOS excluded)
if (/Firefox/i.test(ua) && !/FxiOS/i.test(ua)) {
return 'firefox' // Both Desktop and Android
}

// Safari (macOS supported, iOS/iPadOS excluded)
if (
/Safari/i.test(ua) &&
/Apple Computer/i.test(vendor) &&
!/Chrome|CriOS|Android/i.test(ua)
) {
if (isMacOS) {
return 'safari'
} else {
return null // Identified as Safari, but on mobile/iPad
}
}

// Chromium-based Browsers
// Chromium Rule: Supported on Desktop Only
// (Excludes Chrome Android, Chrome iOS, Edge Mobile, etc.)
if (/Chrome|CriOS|Edg|Vivaldi|Opr|Brave/i.test(ua)) {
// Determine the specific flavor
if (/Edg/i.test(ua)) {
return isMobile ? null : 'edge'
} else if (/Vivaldi/i.test(ua) || /Opr/i.test(ua) || /Brave/i.test(ua)) {
return isMobile ? null : 'chromium'
} else {
return isMobile ? null : 'chrome'
}
}

return null
}

export function getExtensionUrl(browserId: BrowserId, utm?: UtmParams): URL {
const url = URL_MAP[browserId]
return urlWithParams(url, utm || {})
}

export function getExtensionHref(
tool: Tool,
options?: Partial<{ fallbackUrl: string; utm: UtmParams }>,
): string {
const utm: UtmParams = {
utm_source: window.location.hostname,
utm_medium: `tools.embed.${tool}`,
...options?.utm,
}
const fallbackUrl = options?.fallbackUrl || 'https://webmonetization.org'

const browserId = getBrowserSupportForExtension(
navigator.userAgent,
navigator.vendor,
)
if (!browserId) {
console.warn('Using on browser that does not have WM extension support')
return urlWithParams(fallbackUrl, utm).href
}
return getExtensionUrl(browserId, utm).href
}
3 changes: 2 additions & 1 deletion shared/utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "0.0.1",
"private": true,
"devDependencies": {
"@interledger/open-payments": "^7.1.3"
"@interledger/open-payments": "^7.1.3",
"@shared/types": "workspace:^"
}
}