diff --git a/src/components/TopMonthlySponsors.astro b/src/components/TopMonthlySponsors.astro
new file mode 100644
index 00000000..4086d8b0
--- /dev/null
+++ b/src/components/TopMonthlySponsors.astro
@@ -0,0 +1,83 @@
+---
+import featuredSponsors from "../featured-sponsors.json"
+
+/**
+ * Top-N featured organizations by tracked monthly contribution.
+ *
+ * Data comes from `src/featured-sponsors.json`. Entries that have an
+ * explicit `monthlyEquivalent` field are sorted descending and included
+ * in this list. Entries without that field are not shown (they still
+ * render in `` and in the all-sponsors bubble grid).
+ *
+ * The set of tracked entries will grow as `monthlyEquivalent` values are
+ * filled in. The current floor is $200/month, which matches the major-tier
+ * GitHub Sponsors threshold.
+ */
+type Sponsor = {
+ name: string
+ type: string
+ logo: string
+ darklogo: string
+ squareLogo: string
+ url: string
+ github?: string
+ isLeading?: boolean
+ monthlyEquivalent?: number
+}
+
+const sponsors = featuredSponsors as Sponsor[]
+
+interface Props {
+ /** Maximum number of sponsors to show. Defaults to 10. */
+ limit?: number
+}
+
+const { limit = 10 } = Astro.props as Props
+
+const tracked = sponsors
+ .filter((s): s is Sponsor & { monthlyEquivalent: number } =>
+ typeof s.monthlyEquivalent === "number" && s.monthlyEquivalent > 0,
+ )
+ .slice()
+ .sort((a, b) => b.monthlyEquivalent - a.monthlyEquivalent)
+ .slice(0, limit)
+
+const usd = (n: number) =>
+ `$${n.toLocaleString("en-US", { maximumFractionDigits: 0 })}`
+---
+
+{tracked.length > 0 && (
+
+)}
diff --git a/src/featured-sponsors.json b/src/featured-sponsors.json
index 7c510909..5ff8d71c 100644
--- a/src/featured-sponsors.json
+++ b/src/featured-sponsors.json
@@ -6,7 +6,8 @@
"darklogo": "/logos/upsun-darkmode.svg",
"squareLogo": "/logos/upsun-square.svg",
"url": "https://upsun.com",
- "isLeading": false
+ "isLeading": false,
+ "monthlyEquivalent": 200
},
{
"name": "Tag1",
@@ -15,7 +16,8 @@
"darklogo": "/logos/dark-tag1.svg",
"squareLogo": "/logos/tag1-square.svg",
"url": "https://tag1.com",
- "isLeading": false
+ "isLeading": false,
+ "monthlyEquivalent": 200
},
{
"name": "i-gelb",
@@ -25,7 +27,8 @@
"squareLogo": "/logos/i-gelb-square.svg",
"url": "https://i-gelb.net",
"github": "i-gelb",
- "isLeading": false
+ "isLeading": false,
+ "monthlyEquivalent": 200
},
{
"name": "Institute for Advanced Study",
@@ -34,7 +37,8 @@
"darklogo": "/logos/ias-dark.svg",
"squareLogo": "/logos/ias-square.svg",
"url": "https://www.ias.edu/",
- "isLeading": false
+ "isLeading": false,
+ "monthlyEquivalent": 200
},
{
"name": "b13",
diff --git a/src/pages/sponsor.astro b/src/pages/sponsor.astro
new file mode 100644
index 00000000..cb14ee63
--- /dev/null
+++ b/src/pages/sponsor.astro
@@ -0,0 +1,443 @@
+---
+import Layout from "../layouts/Layout.astro"
+import Heading from "../components/Heading.astro"
+import CtaButton from "../components/CtaButton.astro"
+import FeaturedSponsors from "../components/FeaturedSponsors.astro"
+import TopMonthlySponsors from "../components/TopMonthlySponsors.astro"
+import Sponsors from "../components/Sponsors.astro"
+
+const title = `Sponsor DDEV`
+const description = `Help fund DDEV's two full-time maintainers. Monthly recurring sponsorship via GitHub, PayPal, or invoice — live progress, transparent breakdown.`
+
+/**
+ * Live sponsorship totals from the published GitHub Pages snapshot at
+ * https://ddev.github.io/sponsorship-data/data/all-sponsorships.json
+ * (alias: https://ddev.com/s/sponsorship-data.json). Updated daily by
+ * the github-sponsorships.sh script in ddev/sponsorship-data.
+ *
+ * Fetched at build time. If the endpoint is unreachable we render the
+ * page with the most-recent known totals so the build never breaks on a
+ * transient network failure.
+ */
+const SPONSORSHIP_DATA_URL =
+ "https://ddev.github.io/sponsorship-data/data/all-sponsorships.json"
+
+interface SourceTotals {
+ monthly: number
+ sponsors: number
+}
+
+interface SponsorshipSnapshot {
+ github: SourceTotals
+ monthly_invoiced: SourceTotals
+ annual_invoiced_monthly_equivalent: SourceTotals
+ paypal_monthly: number
+ total_monthly: number
+ goal_amount: number
+ progress_percentage: number
+ one_week_ago_monthly: number | null
+ updated_iso: string | null
+ fallback: boolean
+}
+
+const fallback: SponsorshipSnapshot = {
+ github: { monthly: 5484, sponsors: 239 },
+ monthly_invoiced: { monthly: 3048, sponsors: 8 },
+ annual_invoiced_monthly_equivalent: { monthly: 879, sponsors: 9 },
+ paypal_monthly: 45,
+ total_monthly: 9456,
+ goal_amount: 12000,
+ progress_percentage: 78.8,
+ one_week_ago_monthly: 7853,
+ updated_iso: null,
+ fallback: true,
+}
+
+async function fetchSponsorshipData(): Promise {
+ try {
+ const res = await fetch(SPONSORSHIP_DATA_URL, {
+ signal: AbortSignal.timeout(8000),
+ })
+ if (!res.ok) return fallback
+ const data: any = await res.json()
+ const ghDdev = data.github_ddev_sponsorships ?? {}
+ const ghRfay = data.github_rfay_sponsorships ?? {}
+ const mi = data.monthly_invoiced_sponsorships ?? {}
+ const ai = data.annual_invoiced_sponsorships ?? {}
+ return {
+ github: {
+ monthly:
+ (ghDdev.total_monthly_sponsorship ?? 0) +
+ (ghRfay.total_monthly_sponsorship ?? 0),
+ sponsors: (ghDdev.total_sponsors ?? 0) + (ghRfay.total_sponsors ?? 0),
+ },
+ monthly_invoiced: {
+ monthly: mi.total_monthly_sponsorship ?? 0,
+ sponsors: mi.total_sponsors ?? 0,
+ },
+ annual_invoiced_monthly_equivalent: {
+ monthly: ai.monthly_equivalent_sponsorship ?? 0,
+ sponsors: ai.total_sponsors ?? 0,
+ },
+ paypal_monthly: data.paypal_sponsorships ?? 0,
+ total_monthly: data.total_monthly_average_income ?? 0,
+ goal_amount: data.current_goal?.target_amount ?? 12000,
+ progress_percentage: data.current_goal?.progress_percentage ?? 0,
+ one_week_ago_monthly: data.historical_data?.one_week_ago ?? null,
+ updated_iso: data.updated_datetime ?? null,
+ fallback: false,
+ }
+ } catch {
+ return fallback
+ }
+}
+
+const data = await fetchSponsorshipData()
+
+const usd = (n: number) =>
+ `$${n.toLocaleString("en-US", { maximumFractionDigits: 0 })}`
+
+const sevenDayDelta =
+ data.one_week_ago_monthly != null
+ ? data.total_monthly - data.one_week_ago_monthly
+ : null
+
+const updatedHuman = data.updated_iso
+ ? new Date(data.updated_iso).toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ })
+ : null
+
+// Clamp progress for the bar; the real percentage is also shown numerically.
+const barPercent = Math.min(100, Math.max(0, data.progress_percentage))
+
+const sources = [
+ {
+ name: "GitHub Sponsors",
+ amount: data.github.monthly,
+ sponsors: data.github.sponsors,
+ note: "ddev org + rfay",
+ url: "https://github.com/sponsors/ddev",
+ },
+ {
+ name: "Monthly invoiced",
+ amount: data.monthly_invoiced.monthly,
+ sponsors: data.monthly_invoiced.sponsors,
+ note: "direct billing",
+ url: "/contact",
+ },
+ {
+ name: "Annual invoiced",
+ amount: data.annual_invoiced_monthly_equivalent.monthly,
+ sponsors: data.annual_invoiced_monthly_equivalent.sponsors,
+ note: "monthly equivalent",
+ url: "/contact",
+ },
+ {
+ name: "PayPal",
+ amount: data.paypal_monthly,
+ sponsors: null,
+ note: "monthly equivalent",
+ url: "https://www.paypal.com/donate/?hosted_button_id=MCNCSZHC7LHSQ",
+ },
+]
+---
+
+
+
+
+
+ {/* --- Live progress block --- */}
+
+
+
+
+ Monthly recurring sponsorship
+
+
+
+
+
+ {data.progress_percentage.toFixed(1)}%
+
+ of the {usd(data.goal_amount)}/month goal
+ {sevenDayDelta != null && sevenDayDelta !== 0 && (
+ <>
+
+
+ {sevenDayDelta > 0 ? "+" : ""}
+ {usd(sevenDayDelta)} vs. one week ago
+
+ >
+ )}
+
+
+
+
+
+ {updatedHuman && !data.fallback && (
+
+ Data updated daily · last update {updatedHuman} ·{" "}
+
+ view raw JSON
+
+
+ )}
+
+
+ {/* --- Three primary CTAs --- */}
+
+
+ Three ways to sponsor
+
+
+ Any amount helps. Monthly recurring is what funds the maintainers; we
+ list each channel separately so you can pick the one that fits.
+
+
+
+ {/* GitHub Sponsors */}
+
+
+ GitHub Sponsors
+
+
+ For individuals and organizations who already use GitHub. Monthly
+ recurring; tiers from $1 to $530.
+
+
+
+
+ {/* PayPal */}
+
+
+ PayPal
+
+
+ One-time gift or recurring without a GitHub account. Supports any
+ amount.
+
+
+
+
+ {/* Invoice */}
+
+
+ Direct invoice
+
+
+ For organizations with a procurement process. The DDEV Foundation
+ is a US 501(c)(3); invoices and W-9 available on request.
+
+
+
+
+
+
+ {/* --- Source breakdown table --- */}
+
+
+ Where the {usd(data.total_monthly)} comes from
+
+
+ Monthly recurring equivalent, by source. Annual sponsorships are
+ normalized to a monthly figure.
+
+
+
+
+
+
+ | Source |
+
+ Monthly
+ |
+
+ Sponsors
+ |
+
+ Notes
+ |
+
+
+
+ {sources.map((s) => (
+
+ |
+
+ {s.name}
+
+ |
+
+ {usd(s.amount)}
+ |
+
+ {s.sponsors != null ? s.sponsors : "—"}
+ |
+
+ {s.note}
+ |
+
+ ))}
+
+ | Total |
+
+ {usd(data.total_monthly)}
+ |
+
+ —
+ |
+
+ {data.progress_percentage.toFixed(1)}% of {usd(data.goal_amount)} goal
+ |
+
+
+
+
+
+
+ {/* --- Top monthly sponsors (tracked) --- */}
+
+
+ Top monthly sponsors
+
+
+ Featured organizations sorted by tracked monthly contribution. Only
+ entries with a confirmed amount in
+
+ featured-sponsors.json
+
+ are listed here; the full set is below.
+
+
+
+
+ {/* --- Featured organizations --- */}
+
+
+ Featured organizations
+
+
+ Companies whose support keeps DDEV maintained. Want your logo here?
+ Sponsor at the major tier (≥ $200/month on GitHub Sponsors, or contact
+ us for invoicing).
+
+
+
+
+ {/* --- Bubble grid of all sponsors --- */}
+
+
+
+ Every account currently sponsoring DDEV on GitHub, plus our featured
+ organizations.
+
+
+
+
+ {/* --- Closing CTAs + foundation note --- */}
+
+
+
+
+ The DDEV Foundation is a Colorado, USA 501(c)(3) non-profit. See{" "}
+
+ DDEV Foundation
+ {" "}
+ for board, financials, and tax status.
+
+
+
+
diff --git a/src/pages/support-ddev.astro b/src/pages/support-ddev.astro
index 45b12751..ad683c6f 100644
--- a/src/pages/support-ddev.astro
+++ b/src/pages/support-ddev.astro
@@ -17,6 +17,18 @@ const title = `Support DDEV`
+
+
+ Looking to sponsor financially?
+ See ddev.com/sponsor
+ for the three sponsorship channels (GitHub, PayPal, invoice), a live
+ breakdown of where the monthly recurring total comes from, and the
+ current progress toward our $12,000/month goal. This page covers the
+ rest: community contributions, spreading the word, and other ways to
+ help.
+
+
+
@@ -27,7 +39,7 @@ const title = `Support DDEV`
Ready to invest in DDEV's future?