diff --git a/apps/web/public/styles.css b/apps/web/public/styles.css index ee12079..d7916aa 100644 --- a/apps/web/public/styles.css +++ b/apps/web/public/styles.css @@ -157,6 +157,21 @@ pre code { .small { font-size: 0.82rem; } +/* + * The visible half of an affiliate disclosure. It sits inside the link it is + * disclosing, on a plain text link and on the primary order button alike, so + * it inherits colour and steps down only in size and weight. + */ +.aff-mark { + margin-left: 0.4em; + font-size: 0.7em; + font-weight: 400; + letter-spacing: 0.04em; + text-transform: uppercase; + opacity: 0.7; + vertical-align: 0.08em; + cursor: help; +} .visually-hidden, .skip { position: absolute; diff --git a/apps/web/src/views/parts.jsx b/apps/web/src/views/parts.jsx index 23c3c57..2c20e79 100644 --- a/apps/web/src/views/parts.jsx +++ b/apps/web/src/views/parts.jsx @@ -7,6 +7,7 @@ import { fmtGb, fmtMoney, KIND_LABELS, + outbound, paramsFrom, toggle, toggleBucket, @@ -16,6 +17,36 @@ import { raw } from 'hono/html'; /** Shared pieces: the rack-unit row, facet rail, chips, agent panel, sparkline. */ +/** + * A link off the site to a provider. + * + * Routed through a referral endpoint where we have a deal with that provider, + * and labelled as one when it is, because a reader is entitled to know which + * links pay us. `rel` carries `sponsored` in that case, which is what search + * engines ask for on a paid link. + */ +export function Outbound({ url, domain, class: cls, children }) { + const out = outbound(url, domain); + if (!out.href) return null; + return ( + + {children} + {out.affiliate ? : null} + + ); +} + +export function AffiliateMark() { + return ( + + affiliate + + ); +} + export const flag = (code) => /^[A-Z]{2}$/.test(code) ? String.fromCodePoint(...[...code].map((c) => 0x1f1e6 + c.charCodeAt(0) - 65)) diff --git a/apps/web/src/views/providers.jsx b/apps/web/src/views/providers.jsx index 664d9a2..1090af6 100644 --- a/apps/web/src/views/providers.jsx +++ b/apps/web/src/views/providers.jsx @@ -1,7 +1,7 @@ import { config } from '@r4ck/config'; import { countryName, fmtMoney } from '@r4ck/core'; import { Layout } from './Layout.jsx'; -import { AgentPanel, Automation, flag, initials, ProviderCard, Unit } from './parts.jsx'; +import { AgentPanel, Automation, flag, initials, Outbound, ProviderCard, Unit } from './parts.jsx'; const csv = (v) => String(v ?? '') @@ -249,11 +249,9 @@ export function Provider({ user, detail }) {