park
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
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()
|
||||
];
|
||||
Reference in New Issue
Block a user