mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-04 05:08:13 +08:00
Revamp the website's donation page
This commit is contained in:
+190
-202
@@ -2,221 +2,209 @@
|
|||||||
title = "Donate"
|
title = "Donate"
|
||||||
|
|
||||||
[extra]
|
[extra]
|
||||||
css = ["/page/donate.css", "/component/feature-box.css", "/component/feature-icons.css"]
|
css = ["/page/donate.css", "/component/feature-box.css"]
|
||||||
|
js = ["/js/page/donate.js"]
|
||||||
+++
|
+++
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
|
||||||
|
<div class="diptych donate-hero">
|
||||||
<div class="block">
|
<div class="block">
|
||||||
|
|
||||||
# Funding creativity, not corporations
|
# Funding creativity, not corporations
|
||||||
|
|
||||||
**Own your tools. Own your art.** Invest in a sustainable, independent future for high-quality creative software that cannot ever be taken away.
|
**Own your tools. Own your art.** Graphite is 100% built and funded by our community. Invest in a sustainable, independent future for high-quality creative software that cannot ever be taken away.
|
||||||
|
|
||||||
<div class="call-to-action">
|
|
||||||
|
|
||||||
<span>
|
|
||||||
<a href="https://github.com/sponsors/GraphiteEditor" target="_blank" class="button arrow">Donate: GitHub Sponsors</a>
|
|
||||||
<em>Avoids processing fees</em>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span>
|
|
||||||
<a href="#supporter-memberships" class="button arrow">Donate: without an account</a>
|
|
||||||
<em>Start to finish in several seconds</em>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
|
<div class="statistics" data-statistics>
|
||||||
|
<div class="statistic">
|
||||||
|
<span class="value" data-statistics-recurring></span>
|
||||||
|
<span class="label">In memberships</span>
|
||||||
|
<span class="note">This month</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="statistic">
|
||||||
<div class="feature-icons three-wide statistics" data-statistics>
|
<span class="value" data-statistics-members></span>
|
||||||
<div class="feature-icon">
|
<span class="label">Members</span>
|
||||||
<img class="atlas" style="--atlas-index: 34" src="https://static.graphite.art/icons/icon-atlas-roadmap__3.png" alt="" />
|
<span class="note">This month</span>
|
||||||
<span data-statistics-dollars></span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="feature-icon">
|
<div class="statistic">
|
||||||
<img class="atlas" style="--atlas-index: 3" src="https://static.graphite.art/icons/icon-atlas-features__2.png" alt="" />
|
<span class="value" data-statistics-one-time></span>
|
||||||
<span data-statistics-members></span>
|
<span class="label">In one-time gifts</span>
|
||||||
|
<span class="note">Past year</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="feature-icon">
|
<div class="statistic">
|
||||||
<img class="atlas" style="--atlas-index: 47" src="https://static.graphite.art/icons/icon-atlas-roadmap__3.png" alt="" />
|
<span class="value" data-statistics-donors></span>
|
||||||
<span data-statistics-donors></span>
|
<span class="label">One-time donors</span>
|
||||||
|
<span class="note">Past year</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
</div>
|
||||||
(async () => {
|
<div class="donation-picker" id="supporter-memberships">
|
||||||
const element = document.querySelector("[data-statistics]");
|
<div class="frequency">
|
||||||
const dollarsElement = document.querySelector("[data-statistics-dollars]");
|
<label><input type="radio" name="donation-frequency" value="monthly" checked /><span>Monthly</span></label>
|
||||||
const membersElement = document.querySelector("[data-statistics-members]");
|
<label><input type="radio" name="donation-frequency" value="one-time" /><span>One-Time</span></label>
|
||||||
const donorsElement = document.querySelector("[data-statistics-donors]");
|
</div>
|
||||||
if (!dollarsElement || !membersElement || !donorsElement) return;
|
<div class="tier-ladder">
|
||||||
try {
|
<label class="tier"><input type="radio" name="donation-tier" value="quark" /><span class="name">Quark</span><span class="price">$5</span></label>
|
||||||
const response = await fetch("https://graphite.art/sponsorship-stats");
|
<label class="tier"><input type="radio" name="donation-tier" value="proton" /><span class="name">Proton</span><span class="price">$10</span></label>
|
||||||
const json = await response.json();
|
<label class="tier"><input type="radio" name="donation-tier" value="nucleus" /><span class="name">Nucleus</span><span class="price">$15</span></label>
|
||||||
if (!json || !json.recurring || !json.one_time_prior_3_month_sum) throw new Error();
|
<label class="tier"><input type="radio" name="donation-tier" value="carbon" checked /><span class="name">Carbon</span><span class="price">$25</span></label>
|
||||||
const recurringDollars = parseInt(json.recurring.cents) / 100;
|
<label class="tier"><input type="radio" name="donation-tier" value="charcoal" /><span class="name">Charcoal</span><span class="price">$50</span></label>
|
||||||
const oneTimeAverageDollars = parseInt(json.one_time_prior_3_month_sum.cents) / 100 / 3;
|
<label class="tier"><input type="radio" name="donation-tier" value="graphite" /><span class="name">Graphite</span><span class="price">$75</span></label>
|
||||||
dollarsElement.innerText = "$" + Math.round(recurringDollars + oneTimeAverageDollars).toLocaleString("en-US") + " / month";
|
<label class="higher-reveal"><input type="checkbox" name="higher-tiers" /><span>Higher tiers with the greatest impact »</span></label>
|
||||||
membersElement.innerText = json.recurring.count.toLocaleString("en-US") + " members (supporting monthly)";
|
<label class="tier higher"><input type="radio" name="donation-tier" value="graphene" /><span class="name">Graphene</span><span class="price">$100</span></label>
|
||||||
donorsElement.innerText = Math.round(json.one_time_prior_3_month_sum.count / 3).toLocaleString("en-US") + " one-time donors (past month)";
|
<label class="tier higher"><input type="radio" name="donation-tier" value="carbide" /><span class="name">Carbide</span><span class="price">$250</span></label>
|
||||||
// Force repaint to work around Safari bug <https://bugs.webkit.org/show_bug.cgi?id=286403> (remove this and its data attribute when the bug is fixed and widely deployed)
|
<label class="tier higher"><input type="radio" name="donation-tier" value="diamond" /><span class="name">Diamond</span><span class="price">$500</span></label>
|
||||||
element.style.transform = "scale(1)";
|
</div>
|
||||||
} catch {
|
<noscript><style>.amount-ladder { display: none !important; }</style></noscript>
|
||||||
element.remove();
|
<div class="amount-ladder">
|
||||||
}
|
<button type="button" class="amount" data-amount="25">$25</button>
|
||||||
})();
|
<button type="button" class="amount" data-amount="30">$30</button>
|
||||||
</script>
|
<button type="button" class="amount" data-amount="60">$60</button>
|
||||||
|
<button type="button" class="amount" data-amount="100">$100</button>
|
||||||
Graphite is 100% built and funded by the community. Your contributions directly help us level up the scope and speed of the project's development. Resources are put towards infrastructure, operational costs, swag to keep contributors happy and motivated, and outreach like exhibiting at conventions and traveling to conferences to foster industry relationships. Hiring full-time developers is the next crucial milestone.
|
<button type="button" class="amount" data-amount="250">$250</button>
|
||||||
|
<button type="button" class="amount" data-amount="500">$500</button>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
<p class="corporate-link">Sponsoring on behalf of a company? <a href="/contact">Ask about corporate sponsorship.</a></p>
|
||||||
|
<div class="picker-body">
|
||||||
<section id="supporter-memberships" class="feature-box-outer">
|
<div class="payment-controls">
|
||||||
<div class="feature-box-inner">
|
<a href="https://billing.stripe.com/p/login/aEU9EzctSfe3cfK5kk" target="_blank" class="manage">Manage your ongoing membership</a>
|
||||||
|
<div class="payment-method">
|
||||||
<div class="block">
|
<label><input type="radio" name="donation-method" value="direct" checked /><span>Direct Payment</span></label>
|
||||||
|
<label><input type="radio" name="donation-method" value="github" /><span>GitHub Sponsors</span></label>
|
||||||
<h1 class="feature-box-header">Supporter memberships</h1>
|
</div>
|
||||||
|
</div>
|
||||||
---
|
<div class="tier-panel" data-tier="quark">
|
||||||
|
<div class="rewards">
|
||||||
Click a membership level below to pay directly by card, no account needed.
|
<ul>
|
||||||
|
<li class="unlocked">Support Graphite's development</li>
|
||||||
A small fee of 3.6% + 30¢ reduces what we receive each month. If convenient, consider instead using <a href="https://github.com/sponsors/GraphiteEditor" target="_blank">GitHub Sponsors</a> for **no fees**.
|
<li class="unlocked github-only">Shiny GitHub profile achievement<span class="info" title="Awarded for supporting through GitHub Sponsors, unless you opt for private payments."></span></li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
<a href="https://buy.stripe.com/6oE2btfCK9863vybII" class="button arrow action" data-method="direct">Donate $5 monthly</a>
|
||||||
<div class="triptych">
|
<a href="https://github.com/sponsors/GraphiteEditor/sponsorships?tier_id=333371" target="_blank" class="button arrow action" data-method="github">Donate $5 monthly</a>
|
||||||
|
</div>
|
||||||
<a href="https://buy.stripe.com/6oE2btfCK9863vybII" target="_blank" class="block feature-box-narrow">
|
<div class="tier-panel" data-tier="proton">
|
||||||
|
<div class="rewards">
|
||||||
<h1 class="feature-box-header">⭕ “Quark” »</h1>
|
<ul>
|
||||||
|
<li class="unlocked">Members-only Discord channel and gold nametag</li>
|
||||||
**$5 / month**
|
<li class="unlocked">Regular dev sneak-peeks and project files from recent YouTube uploads<span class="info" title="Posted as pinned messages in the members-only Discord channel."></span></li>
|
||||||
|
<li class="github-only">Shiny GitHub profile achievement<span class="info" title="Awarded for supporting through GitHub Sponsors, unless you opt for private payments."></span></li>
|
||||||
- Your GitHub profile unlocks a shiny achievement acknowledging your contribution *(through GitHub Sponsors only)*
|
</ul>
|
||||||
|
</div>
|
||||||
</a>
|
<a href="https://buy.stripe.com/00gdUb62aesq9TW7st" class="button arrow action" data-method="direct">Donate $10 monthly</a>
|
||||||
<a href="https://buy.stripe.com/00gdUb62aesq9TW7st" target="_blank" class="block feature-box-narrow">
|
<a href="https://github.com/sponsors/GraphiteEditor/sponsorships?tier_id=333372" target="_blank" class="button arrow action" data-method="github">Donate $10 monthly</a>
|
||||||
|
</div>
|
||||||
<h1 class="feature-box-header">➕ “Proton” »</h1>
|
<div class="tier-panel" data-tier="nucleus">
|
||||||
|
<div class="rewards">
|
||||||
**$10 / month**
|
<ul>
|
||||||
|
<li class="unlocked">Your name in our update video and site credits<span class="info" title="Shown in the credits of our YouTube update videos and on this website. Your name is subject to reasonable content approval."></span></li>
|
||||||
- Get a **"Member" role** and accompanying **gold-colored nametag on Discord**
|
<li>Members-only Discord channel and gold nametag</li>
|
||||||
- *Plus the lower-tier rewards*
|
<li>Regular dev sneak-peeks and project files from recent YouTube uploads<span class="info" title="Posted as pinned messages in the members-only Discord channel."></span></li>
|
||||||
|
<li class="github-only">Shiny GitHub profile achievement<span class="info" title="Awarded for supporting through GitHub Sponsors, unless you opt for private payments."></span></li>
|
||||||
</a>
|
</ul>
|
||||||
<a href="https://buy.stripe.com/5kAbM38aiacaeac28a" target="_blank" class="block feature-box-narrow">
|
</div>
|
||||||
|
<a href="https://buy.stripe.com/5kAbM38aiacaeac28a" class="button arrow action" data-method="direct">Donate $15 monthly</a>
|
||||||
<h1 class="feature-box-header">⚛️ “Carbon” »</h1>
|
<a href="https://github.com/sponsors/GraphiteEditor/sponsorships?tier_id=333373" target="_blank" class="button arrow action" data-method="github">Donate $15 monthly</a>
|
||||||
|
</div>
|
||||||
**$15 / month**
|
<div class="tier-panel" data-tier="carbon">
|
||||||
|
<div class="rewards">
|
||||||
- Your name/handle listed in the end-of-year **retrospective blog post** thank-you section
|
<ul>
|
||||||
- *Plus the lower-tier rewards*
|
<li class="unlocked">Your name higher in our update video and site credits<span class="info" title="Shown in the credits of our YouTube update videos and on this website. Your name is subject to reasonable content approval."></span></li>
|
||||||
|
<li>Members-only Discord channel and gold nametag</li>
|
||||||
</a>
|
<li>Regular dev sneak-peeks and project files from recent YouTube uploads<span class="info" title="Posted as pinned messages in the members-only Discord channel."></span></li>
|
||||||
|
<li class="github-only">Shiny GitHub profile achievement<span class="info" title="Awarded for supporting through GitHub Sponsors, unless you opt for private payments."></span></li>
|
||||||
<a href="https://buy.stripe.com/28o4jB62a0BA5DGbIL" target="_blank" class="block feature-box-narrow">
|
</ul>
|
||||||
|
</div>
|
||||||
<h1 class="feature-box-header">🧬 “DNA” »</h1>
|
<a href="https://buy.stripe.com/28o4jB62a0BA5DGbIL" class="button arrow action" data-method="direct">Donate $25 monthly</a>
|
||||||
|
<a href="https://github.com/sponsors/GraphiteEditor/sponsorships?tier_id=333374" target="_blank" class="button arrow action" data-method="github">Donate $25 monthly</a>
|
||||||
**$25 / month**
|
</div>
|
||||||
|
<div class="tier-panel" data-tier="charcoal">
|
||||||
- Your **personal name** (or handle) **on the Graphite website and GitHub readme**
|
<div class="rewards">
|
||||||
- Option to be mailed a personal **thank-you card with Graphite stickers** (in the US only)
|
<ul>
|
||||||
- *Plus the lower-tier rewards*
|
<li class="unlocked">Your name higher in our update video and site credits<span class="info" title="Shown in the credits of our YouTube update videos and on this website. Your name is subject to reasonable content approval."></span></li>
|
||||||
|
<li>Members-only Discord channel and gold nametag</li>
|
||||||
</a>
|
<li>Regular dev sneak-peeks and project files from recent YouTube uploads<span class="info" title="Posted as pinned messages in the members-only Discord channel."></span></li>
|
||||||
<a href="https://buy.stripe.com/28o03laiq0BA8PS6os" target="_blank" class="block feature-box-narrow">
|
<li class="github-only">Shiny GitHub profile achievement<span class="info" title="Awarded for supporting through GitHub Sponsors, unless you opt for private payments."></span></li>
|
||||||
|
</ul>
|
||||||
<h1 class="feature-box-header">🌱 “Organism” »</h1>
|
</div>
|
||||||
|
<a href="https://buy.stripe.com/28o03laiq0BA8PS6os" class="button arrow action" data-method="direct">Donate $50 monthly</a>
|
||||||
**$50 / month**
|
<a href="https://github.com/sponsors/GraphiteEditor/sponsorships?tier_id=333375" target="_blank" class="button arrow action" data-method="github">Donate $50 monthly</a>
|
||||||
|
</div>
|
||||||
- Option to be given a public **shout-out of appreciation** from @GraphiteEditor on your choice of social media sites
|
<div class="tier-panel" data-tier="graphite">
|
||||||
- *Plus the lower-tier rewards*
|
<div class="rewards">
|
||||||
|
<ul>
|
||||||
</a>
|
<li class="unlocked">Your name higher in our update video and site credits<span class="info" title="Shown in the credits of our YouTube update videos and on this website. Your name is subject to reasonable content approval."></span></li>
|
||||||
<a href="https://buy.stripe.com/fZedUbduCfwu2ru7sx" target="_blank" class="block feature-box-narrow">
|
<li>Members-only Discord channel and gold nametag</li>
|
||||||
|
<li>Regular dev sneak-peeks and project files from recent YouTube uploads<span class="info" title="Posted as pinned messages in the members-only Discord channel."></span></li>
|
||||||
<h1 class="feature-box-header">🌄 “Biosphere” »</h1>
|
<li class="github-only">Shiny GitHub profile achievement<span class="info" title="Awarded for supporting through GitHub Sponsors, unless you opt for private payments."></span></li>
|
||||||
|
</ul>
|
||||||
**$75 / month**
|
</div>
|
||||||
|
<a href="https://buy.stripe.com/fZedUbduCfwu2ru7sx" class="button arrow action" data-method="direct">Donate $75 monthly</a>
|
||||||
- Your personal name (or handle) may be a **hyperlink** to your personal site or social media profile
|
<a href="https://github.com/sponsors/GraphiteEditor/sponsorships?tier_id=333376" target="_blank" class="button arrow action" data-method="github">Donate $75 monthly</a>
|
||||||
- *Plus the lower-tier rewards*
|
</div>
|
||||||
|
<div class="tier-panel" data-tier="graphene">
|
||||||
</a>
|
<div class="rewards">
|
||||||
|
<ul>
|
||||||
</div>
|
<li class="unlocked">Your name higher in our update video and site credits<span class="info" title="Shown in the credits of our YouTube update videos and on this website. Your name is subject to reasonable content approval."></span></li>
|
||||||
|
<li class="unlocked">Custom hyperlink on your site credits name<span class="info" title="Your link is subject to reasonable content approval."></span></li>
|
||||||
<div class="block action-buttons">
|
<li>Members-only Discord channel and gold nametag</li>
|
||||||
|
<li>Regular dev sneak-peeks and project files from recent YouTube uploads<span class="info" title="Posted as pinned messages in the members-only Discord channel."></span></li>
|
||||||
<a href="https://donate.stripe.com/6oU8wP6m0c2kb2AermbQY0a" target="_blank" class="button arrow">Or make a one-time donation</a>
|
<li class="github-only">Shiny GitHub profile achievement<span class="info" title="Awarded for supporting through GitHub Sponsors, unless you opt for private payments."></span></li>
|
||||||
|
</ul>
|
||||||
[Manage your ongoing membership](https://billing.stripe.com/p/login/aEU9EzctSfe3cfK5kk)
|
</div>
|
||||||
|
<a href="https://buy.stripe.com/7sI6rJ1LU5VUaY05kq" class="button arrow action" data-method="direct">Donate $100 monthly</a>
|
||||||
</div>
|
<a href="https://github.com/sponsors/GraphiteEditor/sponsorships?tier_id=333377" target="_blank" class="button arrow action" data-method="github">Donate $100 monthly</a>
|
||||||
|
</div>
|
||||||
</div>
|
<div class="tier-panel" data-tier="carbide">
|
||||||
</section>
|
<div class="rewards">
|
||||||
|
<ul>
|
||||||
<section id="corporate-sponsorships" class="feature-box-outer">
|
<li class="unlocked">Your name higher in our update video and site credits<span class="info" title="Shown in the credits of our YouTube update videos and on this website. Your name is subject to reasonable content approval."></span></li>
|
||||||
<div class="feature-box-inner">
|
<li class="unlocked">Custom avatar picture with your site credits name<span class="info" title="Your avatar is subject to reasonable content approval."></span></li>
|
||||||
|
<li>Custom hyperlink on your site credits name<span class="info" title="Your link is subject to reasonable content approval."></span></li>
|
||||||
<div class="block">
|
<li>Members-only Discord channel and gold nametag</li>
|
||||||
|
<li>Regular dev sneak-peeks and project files from recent YouTube uploads<span class="info" title="Posted as pinned messages in the members-only Discord channel."></span></li>
|
||||||
<h1 class="feature-box-header">Corporate sponsorships</h1>
|
<li class="github-only">Shiny GitHub profile achievement<span class="info" title="Awarded for supporting through GitHub Sponsors, unless you opt for private payments."></span></li>
|
||||||
|
</ul>
|
||||||
---
|
</div>
|
||||||
|
<a href="https://buy.stripe.com/3cs8zR8ai0BA8PSaEL" class="button arrow action" data-method="direct">Donate $250 monthly</a>
|
||||||
Also available to individuals wanting to make a larger impact. [Reach out](/contact) to pay by invoice or ACH to avoid fees, or for a custom arrangement.
|
<a href="https://github.com/sponsors/GraphiteEditor/sponsorships?tier_id=441886" target="_blank" class="button arrow action" data-method="github">Donate $250 monthly</a>
|
||||||
|
</div>
|
||||||
</div>
|
<div class="tier-panel" data-tier="diamond">
|
||||||
|
<div class="rewards">
|
||||||
<div class="triptych">
|
<ul>
|
||||||
|
<li class="unlocked">Your name higher in our update video and site credits<span class="info" title="Shown in the credits of our YouTube update videos and on this website. Your name is subject to reasonable content approval."></span></li>
|
||||||
<a href="https://buy.stripe.com/7sI6rJ1LU5VUaY05kq" target="_blank" class="block feature-box-narrow">
|
<li class="unlocked">A spoken personal thank-you during update video credits</li>
|
||||||
|
<li>Custom avatar picture with your site credits name<span class="info" title="Your avatar is subject to reasonable content approval."></span></li>
|
||||||
<h1 class="feature-box-header">🪨 “Charcoal” »</h1>
|
<li>Custom hyperlink on your site credits name<span class="info" title="Your link is subject to reasonable content approval."></span></li>
|
||||||
|
<li>Members-only Discord channel and gold nametag</li>
|
||||||
**$100 / month**
|
<li>Regular dev sneak-peeks and project files from recent YouTube uploads<span class="info" title="Posted as pinned messages in the members-only Discord channel."></span></li>
|
||||||
|
<li class="github-only">Shiny GitHub profile achievement<span class="info" title="Awarded for supporting through GitHub Sponsors, unless you opt for private payments."></span></li>
|
||||||
- Your **company name** may be shown **on the Graphite website and GitHub readme** starting at this tier level
|
</ul>
|
||||||
- *Plus the lower-tier rewards for members*
|
</div>
|
||||||
|
<a href="https://buy.stripe.com/fZeaHZ76e0BAeaccMU" class="button arrow action" data-method="direct">Donate $500 monthly</a>
|
||||||
</a>
|
<a href="https://github.com/sponsors/GraphiteEditor/sponsorships?tier_id=441888" target="_blank" class="button arrow action" data-method="github">Donate $500 monthly</a>
|
||||||
<a href="https://buy.stripe.com/3cs8zR8ai0BA8PSaEL" target="_blank" class="block feature-box-narrow">
|
</div>
|
||||||
|
<div class="tier-panel" data-frequency="one-time">
|
||||||
<h1 class="feature-box-header">🛡️ “Carbide” »</h1>
|
<div class="rewards">
|
||||||
|
<ul>
|
||||||
**$250 / month**
|
<li>Select a common amount from above or customize it below</li>
|
||||||
|
<li>We're currently not set up to fulfill membership rewards for one-time donors, but your selfless generosity is appreciated</li>
|
||||||
- Your name on the website and readme may be a **hyperlink** to your company/personal site
|
</ul>
|
||||||
- *Plus the lower-tier rewards for members*
|
</div>
|
||||||
|
<form class="one-time-entry" method="POST" action="https://graphite.art/donate/create-donation-session">
|
||||||
</a>
|
<div class="amount-entry">
|
||||||
<a href="https://buy.stripe.com/fZeaHZ76e0BAeaccMU" target="_blank" class="block feature-box-narrow">
|
<label class="amount-field"><span class="currency">$</span><input type="number" name="amount" value="100" min="3" max="10000" step="0.01" required aria-label="Donation amount in US dollars" data-donation-amount /></label>
|
||||||
|
<button type="submit" class="button arrow action" data-method="direct">Donate</button>
|
||||||
<h1 class="feature-box-header">💎 “Diamond” »</h1>
|
<a href="https://github.com/sponsors/GraphiteEditor/sponsorships?frequency=one-time&amount=100" target="_blank" class="button arrow action" data-method="github" data-github-one-time>Donate</a>
|
||||||
|
</div>
|
||||||
**$500 / month**
|
</form>
|
||||||
|
</div>
|
||||||
- Your name and link on the website and readme may instead be a **hyperlinked logo**
|
</div>
|
||||||
- *Plus the lower-tier rewards for members*
|
<div class="picker-footer">
|
||||||
|
<p class="method-note" data-method="direct">Pay by card or other methods in just a few clicks, no account needed.</p>
|
||||||
</a>
|
<p class="method-note" data-method="github">GitHub subsidizes our processing fees so your full amount reaches us.</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="block action-buttons">
|
|
||||||
|
|
||||||
<a href="https://donate.stripe.com/6oU8wP6m0c2kb2AermbQY0a" target="_blank" class="button arrow">Or make a one-time donation</a>
|
|
||||||
|
|
||||||
[Manage your ongoing membership](https://billing.stripe.com/p/login/aEU9EzctSfe3cfK5kk)
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ export default defineConfig([
|
|||||||
// Ignore generated directories
|
// Ignore generated directories
|
||||||
"node_modules/",
|
"node_modules/",
|
||||||
"public/",
|
"public/",
|
||||||
|
"static/wasm/",
|
||||||
// Ignore vendored code
|
// Ignore vendored code
|
||||||
"static/*.js",
|
"static/*.js",
|
||||||
// Don't ignore JS and TS dotfiles in this folder
|
// Don't ignore JS and TS dotfiles in this folder
|
||||||
|
|||||||
+402
-70
@@ -1,109 +1,441 @@
|
|||||||
.call-to-action.call-to-action.call-to-action {
|
// ==================================
|
||||||
display: flex;
|
// HERO SPLIT BETWEEN COPY AND PICKER
|
||||||
flex-wrap: wrap;
|
// ==================================
|
||||||
flex-direction: row;
|
|
||||||
gap: calc(var(--font-size-link) * 0.8);
|
|
||||||
margin: calc(40 * var(--variable-px)) 0;
|
|
||||||
|
|
||||||
span {
|
.diptych.donate-hero {
|
||||||
display: flex;
|
align-items: flex-start;
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
em {
|
> .block {
|
||||||
text-align: center;
|
flex: 1 1 420px;
|
||||||
margin-top: 0.5em;
|
|
||||||
|
h1 {
|
||||||
|
text-wrap: balance;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.button {
|
.statistics {
|
||||||
margin: 0;
|
display: grid;
|
||||||
}
|
grid-template-columns: repeat(2, 1fr);
|
||||||
}
|
// Equal rows keep the two halves balanced against the rule between them
|
||||||
|
grid-auto-rows: 1fr;
|
||||||
|
// The copy column aligns its children to the start, so this has to opt into the full width
|
||||||
|
align-self: stretch;
|
||||||
|
margin-top: calc(40 * var(--variable-px));
|
||||||
|
|
||||||
.statistics:has(span:empty) {
|
// Hides these while the stats API request is still in flight or has failed
|
||||||
|
&:has(.value:empty) {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
#supporter-memberships,
|
.statistic {
|
||||||
#corporate-sponsorships {
|
|
||||||
.triptych {
|
|
||||||
gap: 10px;
|
|
||||||
margin-top: 10px;
|
|
||||||
|
|
||||||
a {
|
|
||||||
flex-basis: calc(100% / 3 - 10px - (var(--feature-box-padding) * var(--variable-px)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.triptych + .block,
|
|
||||||
.feature-box-inner > .block + :is(.block, .triptych) {
|
|
||||||
margin-top: calc(var(--feature-box-padding) / 2 * var(--variable-px));
|
|
||||||
}
|
|
||||||
|
|
||||||
.triptych + .block {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
padding: calc(20 * var(--variable-px)) 20px;
|
||||||
|
|
||||||
|
// Each row gets its own rule, inset so the two break apart at the row boundary
|
||||||
|
&:nth-child(odd) {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
width: var(--border-thickness);
|
||||||
|
top: calc(20 * var(--variable-px));
|
||||||
|
bottom: calc(20 * var(--variable-px));
|
||||||
|
right: 0;
|
||||||
|
background-color: var(--color-cloud);
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-buttons {
|
|
||||||
gap: calc(var(--feature-box-padding) / 4 * var(--variable-px)) calc(var(--feature-box-padding) * var(--variable-px));
|
|
||||||
flex-wrap: wrap;
|
|
||||||
|
|
||||||
p {
|
|
||||||
text-align: left;
|
|
||||||
text-justify: auto;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 1280px) {
|
.value {
|
||||||
.triptych a {
|
font-family: "Bona Nova", Palatino, serif;
|
||||||
// Half width, minus own padding on both sides, minus the gap
|
font-feature-settings: "lnum";
|
||||||
flex-basis: calc(50% - (var(--feature-box-padding) * var(--variable-px)) - 10px);
|
font-weight: 700;
|
||||||
|
line-height: 1.25;
|
||||||
|
font-size: calc(1rem * 20 / 9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.label,
|
||||||
|
.note {
|
||||||
|
font-size: calc(1rem * 7 / 9);
|
||||||
|
font-weight: 800;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--color-walnut);
|
||||||
|
text-wrap: balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 400px) {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
|
||||||
|
.statistic:nth-child(odd)::after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 640px) {
|
// ===============
|
||||||
.triptych a {
|
// DONATION PICKER
|
||||||
flex-basis: 100%;
|
// ===============
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.feature-box-narrow {
|
.donation-picker {
|
||||||
min-width: 0;
|
// Shrinks the checkout button, which is the only thing in here sized off this variable
|
||||||
background-color: var(--color-fog);
|
--font-size-link: calc(1rem * 10 / 9);
|
||||||
|
|
||||||
|
flex: 1 1 420px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
padding: calc(var(--feature-box-padding) / 2 * var(--variable-px));
|
padding: calc(var(--feature-box-padding) / 2 * var(--variable-px));
|
||||||
text-decoration: none;
|
background-color: var(--color-cloud);
|
||||||
color: var(--color-navy);
|
background-image: url("https://static.graphite.art/textures/noise.png");
|
||||||
|
background-blend-mode: overlay;
|
||||||
|
background-position: center;
|
||||||
|
|
||||||
|
// Every visibility rule below is driven by these, so they're taken out of the layout without losing keyboard focusability
|
||||||
|
input:is([type="radio"], [type="checkbox"]) {
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
opacity: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
label:has(input:is([type="radio"], [type="checkbox"])) {
|
||||||
|
background-color: var(--color-fog);
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: var(--color-lemon);
|
background-color: var(--color-lemon);
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
&:has(input:checked) {
|
||||||
// Compensates for emoji starting with some left spacing
|
background-color: var(--color-navy);
|
||||||
text-indent: -0.2em;
|
color: var(--color-parchment);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:has(input:focus-visible) {
|
||||||
|
outline: var(--border-thickness) solid var(--color-crimson);
|
||||||
|
outline-offset: var(--border-thickness);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.frequency,
|
||||||
|
.payment-method {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
|
label {
|
||||||
|
flex: 1 1 0;
|
||||||
|
text-align: center;
|
||||||
|
padding: 0.4em 0;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.frequency {
|
||||||
|
margin-bottom: calc(20 * var(--variable-px));
|
||||||
|
}
|
||||||
|
|
||||||
|
.tier-ladder,
|
||||||
|
.amount-ladder {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
|
@media screen and (max-width: 420px) {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount-ladder {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0.5em 0.25em;
|
||||||
|
font: inherit;
|
||||||
|
font-weight: 800;
|
||||||
|
color: inherit;
|
||||||
|
border: none;
|
||||||
|
background-color: var(--color-fog);
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--color-lemon);
|
||||||
|
}
|
||||||
|
|
||||||
|
&[aria-pressed="true"] {
|
||||||
|
background-color: var(--color-navy);
|
||||||
|
color: var(--color-parchment);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus-visible {
|
||||||
|
outline: var(--border-thickness) solid var(--color-crimson);
|
||||||
|
outline-offset: var(--border-thickness);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tier-ladder {
|
||||||
|
.tier {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
padding: 0.5em 0.25em;
|
||||||
|
|
||||||
|
.name {
|
||||||
|
font-weight: 800;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: calc(1rem * 7 / 9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.price {
|
||||||
|
font-size: calc(1rem * 8 / 9);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.higher-reveal {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
padding: 0.4em 0;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 800;
|
||||||
|
font-size: calc(1rem * 7 / 9);
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tier.higher {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:has(.higher-reveal input:checked) {
|
||||||
|
.higher-reveal {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tier.higher {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.corporate-link {
|
||||||
|
text-align: left;
|
||||||
|
text-justify: auto;
|
||||||
|
font-size: calc(1rem * 7 / 9);
|
||||||
|
}
|
||||||
|
|
||||||
|
// One toggle serves every tier, yet belongs between each tier's rewards and its button, so fixed rows interleave the two
|
||||||
|
.picker-body {
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: auto auto auto;
|
||||||
|
row-gap: 10px;
|
||||||
|
margin-top: calc(20 * var(--variable-px));
|
||||||
|
|
||||||
|
> .tier-panel {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rewards {
|
||||||
|
grid-area: 1 / 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
padding-left: 1em;
|
padding-left: 1.25em;
|
||||||
font-size: calc(7 / 9 * 1em);
|
font-size: calc(1rem * 8 / 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Marks what's new in this tier compared to its predecessor
|
||||||
|
li.unlocked {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 1.4em;
|
||||||
|
height: 1.4em;
|
||||||
|
margin-left: 0.5em;
|
||||||
|
vertical-align: middle;
|
||||||
|
position: relative;
|
||||||
|
top: -0.15em;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: var(--color-navy);
|
||||||
|
color: var(--color-parchment);
|
||||||
|
font-size: calc(1rem * 5 / 9);
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1;
|
||||||
|
cursor: help;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: "?";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .payment-controls {
|
||||||
|
grid-area: 2 / 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
|
// Carried by the toggle rather than the wrapper, so the separation above it never changes
|
||||||
|
.payment-method {
|
||||||
|
margin-top: calc(20 * var(--variable-px));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.manage {
|
||||||
|
align-self: flex-end;
|
||||||
|
margin-top: calc(20 * var(--variable-px));
|
||||||
|
font-size: calc(1rem * 7 / 9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.action {
|
||||||
|
grid-area: 3 / 1;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The amount field serves both methods, so only the buttons beside it swap
|
||||||
|
.one-time-entry {
|
||||||
|
grid-area: 3 / 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
background-color: var(--color-fog);
|
background-color: var(--color-fog);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.button {
|
||||||
|
font-family: inherit;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount-entry {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
|
// The currency sign lives inside the box, so the border belongs to this wrapper instead of the input
|
||||||
|
.amount-field {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0 0.5em;
|
||||||
|
font-weight: 800;
|
||||||
|
color: var(--color-navy);
|
||||||
|
font-size: var(--font-size-link);
|
||||||
|
height: calc(var(--font-size-link) * 2);
|
||||||
|
border: var(--border-thickness) solid var(--color-navy);
|
||||||
|
background-color: white;
|
||||||
|
cursor: text;
|
||||||
|
|
||||||
|
&:focus-within {
|
||||||
|
outline: var(--border-thickness) solid var(--color-crimson);
|
||||||
|
outline-offset: var(--border-thickness);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#supporter-memberships {
|
.currency {
|
||||||
background-color: var(--color-mustard);
|
margin-right: 0.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
#corporate-sponsorships {
|
input {
|
||||||
background-color: var(--color-ale);
|
width: 6ch;
|
||||||
margin-top: 0;
|
padding: 0;
|
||||||
|
font: inherit;
|
||||||
|
color: inherit;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
appearance: textfield;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-outer-spin-button,
|
||||||
|
&::-webkit-inner-spin-button {
|
||||||
|
appearance: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.picker-footer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5em;
|
||||||
|
font-size: calc(1rem * 7 / 9);
|
||||||
|
|
||||||
|
p {
|
||||||
|
text-align: left;
|
||||||
|
text-justify: auto;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.donation-picker:has([value="quark"]:checked) .tier-panel[data-tier="quark"],
|
||||||
|
.donation-picker:has([value="proton"]:checked) .tier-panel[data-tier="proton"],
|
||||||
|
.donation-picker:has([value="nucleus"]:checked) .tier-panel[data-tier="nucleus"],
|
||||||
|
.donation-picker:has([value="carbon"]:checked) .tier-panel[data-tier="carbon"],
|
||||||
|
.donation-picker:has([value="charcoal"]:checked) .tier-panel[data-tier="charcoal"],
|
||||||
|
.donation-picker:has([value="graphite"]:checked) .tier-panel[data-tier="graphite"],
|
||||||
|
.donation-picker:has([value="graphene"]:checked) .tier-panel[data-tier="graphene"],
|
||||||
|
.donation-picker:has([value="carbide"]:checked) .tier-panel[data-tier="carbide"],
|
||||||
|
.donation-picker:has([value="diamond"]:checked) .tier-panel[data-tier="diamond"] {
|
||||||
|
display: contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
.donation-picker:has([value="one-time"]:checked) {
|
||||||
|
.tier-ladder {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount-ladder {
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.picker-body .tier-panel[data-tier] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tier-panel[data-frequency="one-time"] {
|
||||||
|
display: contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
// There is no ongoing membership to manage from a one-time gift
|
||||||
|
.manage {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.donation-picker:has([value="direct"]:checked) .github-only {
|
||||||
|
color: Rgb(from var(--color-navy) r g b / 0.33);
|
||||||
|
}
|
||||||
|
|
||||||
|
.donation-picker:has([value="github"]:checked) .manage {
|
||||||
|
color: Rgb(from var(--color-crimson) r g b / 0.33);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.donation-picker:has([value="direct"]:checked) :is(.action, .method-note)[data-method="direct"],
|
||||||
|
.donation-picker:has([value="github"]:checked) :is(.action, .method-note)[data-method="github"] {
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
const statisticsRequest = fetch("https://graphite.art/donate/sponsorship-stats").then((response) => response.json());
|
||||||
|
|
||||||
|
window.addEventListener("DOMContentLoaded", () => {
|
||||||
|
setUpAmountPresets();
|
||||||
|
showStatistics();
|
||||||
|
});
|
||||||
|
|
||||||
|
function setUpAmountPresets() {
|
||||||
|
const amountField = /** @type {HTMLInputElement | null} */ (document.querySelector("[data-donation-amount]"));
|
||||||
|
const presetButtons = /** @type {NodeListOf<HTMLElement>} */ (document.querySelectorAll("[data-amount]"));
|
||||||
|
const githubOneTime = /** @type {HTMLAnchorElement | null} */ (document.querySelector("[data-github-one-time]"));
|
||||||
|
if (!amountField || presetButtons.length === 0) return;
|
||||||
|
|
||||||
|
const syncAmount = () => {
|
||||||
|
presetButtons.forEach((button) => button.setAttribute("aria-pressed", String(button.dataset.amount === amountField.value)));
|
||||||
|
|
||||||
|
if (!githubOneTime) return;
|
||||||
|
|
||||||
|
const amount = Number(amountField.value);
|
||||||
|
const suffix = Number.isFinite(amount) && amount > 0 ? `&amount=${amount}` : "";
|
||||||
|
githubOneTime.href = `https://github.com/sponsors/GraphiteEditor/sponsorships?frequency=one-time${suffix}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
presetButtons.forEach((button) => {
|
||||||
|
button.addEventListener("click", () => {
|
||||||
|
amountField.value = button.dataset.amount || "";
|
||||||
|
syncAmount();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
amountField.addEventListener("input", syncAmount);
|
||||||
|
|
||||||
|
syncAmount();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function showStatistics() {
|
||||||
|
const element = /** @type {HTMLElement | null} */ (document.querySelector("[data-statistics]"));
|
||||||
|
const recurringElement = /** @type {HTMLElement | null} */ (document.querySelector("[data-statistics-recurring]"));
|
||||||
|
const membersElement = /** @type {HTMLElement | null} */ (document.querySelector("[data-statistics-members]"));
|
||||||
|
const oneTimeElement = /** @type {HTMLElement | null} */ (document.querySelector("[data-statistics-one-time]"));
|
||||||
|
const donorsElement = /** @type {HTMLElement | null} */ (document.querySelector("[data-statistics-donors]"));
|
||||||
|
if (!element || !recurringElement || !membersElement || !oneTimeElement || !donorsElement) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const json = await statisticsRequest;
|
||||||
|
if (!json || !json.recurring || !json.one_time_prior_12_month_sum) throw new Error();
|
||||||
|
|
||||||
|
const number = (/** @type {number} */ value) => Math.round(value).toLocaleString("en-US", { useGrouping: "min2" });
|
||||||
|
const dollars = (/** @type {number} */ value) => `$${number(value)}`;
|
||||||
|
|
||||||
|
recurringElement.innerText = dollars(parseInt(json.recurring.cents) / 100);
|
||||||
|
membersElement.innerText = number(json.recurring.count);
|
||||||
|
oneTimeElement.innerText = dollars(parseInt(json.one_time_prior_12_month_sum.cents) / 100);
|
||||||
|
donorsElement.innerText = number(json.one_time_prior_12_month_sum.count);
|
||||||
|
|
||||||
|
// Force repaint to work around Safari bug <https://bugs.webkit.org/show_bug.cgi?id=286403> (remove this and its data attribute when the bug is fixed and widely deployed)
|
||||||
|
element.style.transform = "scale(1)";
|
||||||
|
} catch {
|
||||||
|
element.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -152,7 +152,7 @@
|
|||||||
<a href="/press" class="link not-uppercase">Press</a>
|
<a href="/press" class="link not-uppercase">Press</a>
|
||||||
<a href="/contact" class="link not-uppercase">Contact</a>
|
<a href="/contact" class="link not-uppercase">Contact</a>
|
||||||
</nav>
|
</nav>
|
||||||
<span>Copyright © {{ now() | date(format = "%Y") }} Graphite Labs, LLC (an open source community organization)</span>
|
<span>Copyright © {{ now() | date(format = "%Y") }} Graphite Labs, an Open Source Community Organization</span>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
// Ignore generated directories
|
// Ignore generated directories
|
||||||
"node_modules",
|
"node_modules",
|
||||||
"public",
|
"public",
|
||||||
|
"static/wasm",
|
||||||
// Ignore vendored code
|
// Ignore vendored code
|
||||||
"static/*.js"
|
"static/*.js"
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user