This repository has been archived on 2026-08-10. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
drizzli/src/lib/supporter/config.ts
T
2026-08-07 10:58:30 +02:00

87 lines
3.5 KiB
TypeScript

import * as m from '$lib/paraglide/messages';
/**
* Supporter configuration.
*
* The frontend stays fully static and open source; the only server piece is the
* tiny `drizzli-paywall` verify API (a separate, self-hosted repo). Point the
* build at your deployment with the `VITE_SUPPORTER_*` env vars (e.g. in a
* `.env` file), otherwise the sensible drizz.li defaults are used. The
* pre-rename `VITE_PAYWALL_*` names still work.
*/
const env = import.meta.env as Record<string, string | undefined>;
const stripTrailingSlash = (url: string): string => url.replace(/\/+$/, '');
/**
* Master switch for the supporter features. While this is `false` everything
* supporter-related is parked: the nav entry points are hidden, no key is
* verified, and every gated page renders as if the visitor were a supporter.
* The logic stays in place — set `VITE_SUPPORTER_ENABLED=true` (or default this
* to `true`) to bring it back.
*/
export const SUPPORTER_ENABLED = env.VITE_SUPPORTER_ENABLED === 'true';
/** Base URL of the self-hosted verify API (drizzli-paywall). */
export const SUPPORTER_API_BASE = stripTrailingSlash(
env.VITE_SUPPORTER_API_BASE ?? env.VITE_PAYWALL_API_BASE ?? 'https://support.drizz.li'
);
/** Where prospective supporters go to sign up (the verify API's signup form). */
export const SIGNUP_URL =
env.VITE_SUPPORTER_SIGNUP_URL ?? env.VITE_PAYWALL_SIGNUP_URL ?? `${SUPPORTER_API_BASE}/`;
// ─── Location-based pricing ──────────────────────────────────────────────────
// The signup form charges 3 in the visitor's currency (EUR / USD / CHF), picked
// from their location. Mirror that here so the supporter copy matches. Detection
// is timezone/locale based (no network geo lookup) and guarded for SSR.
const CURRENCY_SYMBOL: Record<string, string> = { EUR: '€', USD: '$', CHF: 'CHF' };
const US_ZONES =
/^America\/(New_York|Detroit|Chicago|Denver|Boise|Phoenix|Los_Angeles|Anchorage|Adak|Juneau|Sitka|Nome|Yakutat|Menominee|Indiana|Kentucky|North_Dakota)/;
export type SupporterCurrency = 'EUR' | 'USD' | 'CHF';
export function detectCurrency(): SupporterCurrency {
if (typeof Intl === 'undefined') return 'EUR';
let tz = '';
try {
tz = Intl.DateTimeFormat().resolvedOptions().timeZone || '';
} catch {
/* ignore */
}
if (/Zurich|Vaduz/.test(tz)) return 'CHF';
let region = '';
try {
if (typeof navigator !== 'undefined') {
region = new Intl.Locale(navigator.language).maximize().region || '';
}
} catch {
/* ignore */
}
if (region === 'CH') return 'CHF';
if (region === 'US' || US_ZONES.test(tz)) return 'USD';
return 'EUR';
}
/** Display price for the locked panel, e.g. "€3 / month" or "CHF 3 / Monat". */
export function getSupporterPrice(): string {
// VITE_PREMIUM_PRICE is the pre-rename name, still honoured so an existing
// deployment's .env keeps working.
const configured = env.VITE_SUPPORTER_PRICE ?? env.VITE_PREMIUM_PRICE;
if (configured) return configured;
const currency = detectCurrency();
const symbol = CURRENCY_SYMBOL[currency];
const amount = currency === 'CHF' ? `${symbol} 3` : `${symbol}3`;
return m.supporter_price_per_month({ amount });
}
/** Short, human list of what supporting unlocks (shown on the locked panel).
* A function, not a constant: the copy has to follow the active locale. */
export const SUPPORTER_PERKS = (): string[] => [
m.supporter_perk_historical(),
m.supporter_perk_seasonal(),
m.supporter_perk_future()
];