mirror of
https://github.com/HananoshikaYomaru/openfreebooks.git
synced 2026-11-12 20:45:52 +00:00
Add GitHub sponsors support and enhance contributing page: Introduce a new script for syncing GitHub sponsors in package.json. Update contributing.md to acknowledge contributors and sponsors, and enhance the contributing page with a dedicated section for sponsors. Improve styles for sponsor-related content in SCSS files and update templates to include sponsor information across relevant pages.
This commit is contained in:
parent
1a26d53730
commit
78180176b1
15 changed files with 288 additions and 18 deletions
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
github: HananoshikaYomaru
|
||||||
|
|
@ -2,3 +2,6 @@
|
||||||
title = "Contribute"
|
title = "Contribute"
|
||||||
template = "contributing.html"
|
template = "contributing.html"
|
||||||
+++
|
+++
|
||||||
|
|
||||||
|
Open Free Books is sustained by contributors and sponsors.
|
||||||
|
Thank you to everyone supporting this mission through [GitHub Sponsors](https://github.com/sponsors/HananoshikaYomaru).
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
"id": "how-different",
|
"id": "how-different",
|
||||||
"type": "comparison",
|
"type": "comparison",
|
||||||
"question": "How is Open Free Books different from LibreTexts, Open Textbook Library, Project Gutenberg, and OpenStax?",
|
"question": "How is Open Free Books different from LibreTexts, Open Textbook Library, Project Gutenberg, and OpenStax?",
|
||||||
"intro": "We respect these projects — they solve different problems. On many platforms, you find lots of different books for a single subject. With Open Free Books, there's just one textbook per subject—designed to be comprehensive so people everywhere can use it for any curriculum. That way, you don't need to pick between competing choices—you can just focus on learning. Oh, so this platform usually only provides static HTML without any interaction or just a PDF, but in OpenFreeBooks we have interactive demos An alleged map that are tailor made to visualize complex idea in simple ways.",
|
"intro": "We respect these projects — they solve different problems. On many platforms, you find lots of different books for a single subject. With Open Free Books, there's just one textbook per subject—designed to be comprehensive so people everywhere can use it for any curriculum. That way, you don't need to pick between competing choices—you can just focus on learning. Also these platforms usually only provide static HTML without any interaction or just PDFs, but in OpenFreeBooks we have interactive demos and knowledge maps that are tailor made to visualize complex idea in simple ways.",
|
||||||
"peers": [
|
"peers": [
|
||||||
{
|
{
|
||||||
"name": "LibreTexts",
|
"name": "LibreTexts",
|
||||||
|
|
|
||||||
20
data/github-sponsors.json
Normal file
20
data/github-sponsors.json
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"title": "GitHub Sponsors",
|
||||||
|
"intro": "Supporters who help keep Open Free Books free and open for learners everywhere.",
|
||||||
|
"profile_url": "https://github.com/sponsors/HananoshikaYomaru",
|
||||||
|
"fetched_at": "2026-05-21T18:06:17.197Z",
|
||||||
|
"sponsors": [
|
||||||
|
{
|
||||||
|
"login": "cybersader",
|
||||||
|
"name": "cybersader",
|
||||||
|
"avatar": "https://avatars.githubusercontent.com/u/106132469?u=12a0dcd73451d3369c414222b2a3b052938aa0e8&v=4",
|
||||||
|
"url": "https://github.com/cybersader"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "judej",
|
||||||
|
"name": "judej",
|
||||||
|
"avatar": "https://avatars.githubusercontent.com/u/547753?u=26add01b0f15c3a119bb78b37107567349620a34&v=4",
|
||||||
|
"url": "https://github.com/judej"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"sync:chapters": "bun scripts/sync-chapters.ts",
|
"sync:chapters": "bun scripts/sync-chapters.ts",
|
||||||
|
"sync:sponsors": "bun scripts/fetch-github-sponsors.ts",
|
||||||
"generate:site-metadata": "bun scripts/generate-site-metadata.ts",
|
"generate:site-metadata": "bun scripts/generate-site-metadata.ts",
|
||||||
"build:js": "bun run sync:chapters && vite build",
|
"build:js": "bun run sync:chapters && vite build",
|
||||||
"build:site": "bun run generate:site-metadata && zola build && bun run index:search",
|
"build:site": "bun run generate:site-metadata && zola build && bun run index:search",
|
||||||
|
|
|
||||||
145
scripts/fetch-github-sponsors.ts
Normal file
145
scripts/fetch-github-sponsors.ts
Normal file
|
|
@ -0,0 +1,145 @@
|
||||||
|
import { mkdir, writeFile } from "node:fs/promises";
|
||||||
|
import { dirname, join } from "node:path";
|
||||||
|
|
||||||
|
type GraphQLError = {
|
||||||
|
message?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SponsorNode = {
|
||||||
|
sponsorEntity?: {
|
||||||
|
login?: string;
|
||||||
|
avatarUrl?: string;
|
||||||
|
url?: string;
|
||||||
|
} | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SponsorsConnection = {
|
||||||
|
pageInfo?: {
|
||||||
|
hasNextPage?: boolean;
|
||||||
|
endCursor?: string | null;
|
||||||
|
};
|
||||||
|
nodes?: SponsorNode[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type GraphQLResponse = {
|
||||||
|
data?: {
|
||||||
|
user?: {
|
||||||
|
sponsorshipsAsMaintainer?: SponsorsConnection;
|
||||||
|
} | null;
|
||||||
|
};
|
||||||
|
errors?: GraphQLError[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type SponsorRecord = {
|
||||||
|
login: string;
|
||||||
|
name: string;
|
||||||
|
avatar: string;
|
||||||
|
url: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ROOT = join(import.meta.dir, "..");
|
||||||
|
const OUTPUT_PATH = join(ROOT, "data", "github-sponsors.json");
|
||||||
|
const SPONSORABLE_LOGIN = "HananoshikaYomaru";
|
||||||
|
|
||||||
|
async function fetchSponsorPage(token: string, after: string | null): Promise<SponsorsConnection> {
|
||||||
|
const query = `
|
||||||
|
query SponsorsAsMaintainer($login: String!, $after: String) {
|
||||||
|
user(login: $login) {
|
||||||
|
sponsorshipsAsMaintainer(first: 100, after: $after, includePrivate: false) {
|
||||||
|
pageInfo {
|
||||||
|
hasNextPage
|
||||||
|
endCursor
|
||||||
|
}
|
||||||
|
nodes {
|
||||||
|
sponsorEntity {
|
||||||
|
... on User {
|
||||||
|
login
|
||||||
|
avatarUrl
|
||||||
|
url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const response = await fetch("https://api.github.com/graphql", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"User-Agent": "openfreebooks-sponsor-sync",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
query,
|
||||||
|
variables: {
|
||||||
|
login: SPONSORABLE_LOGIN,
|
||||||
|
after,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`GitHub GraphQL request failed (${response.status} ${response.statusText})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const payload = (await response.json()) as GraphQLResponse;
|
||||||
|
if (payload.errors?.length) {
|
||||||
|
const message = payload.errors.map((err) => err.message).filter(Boolean).join("; ");
|
||||||
|
throw new Error(`GitHub GraphQL returned errors: ${message}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const connection = payload.data?.user?.sponsorshipsAsMaintainer;
|
||||||
|
return connection ?? { nodes: [], pageInfo: { hasNextPage: false, endCursor: null } };
|
||||||
|
}
|
||||||
|
|
||||||
|
function toSponsorRecord(node: SponsorNode): SponsorRecord | null {
|
||||||
|
const entity = node.sponsorEntity;
|
||||||
|
if (!entity?.login || !entity.avatarUrl || !entity.url) return null;
|
||||||
|
|
||||||
|
return {
|
||||||
|
login: entity.login,
|
||||||
|
name: entity.login,
|
||||||
|
avatar: entity.avatarUrl,
|
||||||
|
url: entity.url,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const token = process.env.GITHUB_TOKEN?.trim();
|
||||||
|
if (!token) {
|
||||||
|
throw new Error("GITHUB_TOKEN is required to fetch GitHub Sponsors.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const sponsors: SponsorRecord[] = [];
|
||||||
|
let after: string | null = null;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const connection = await fetchSponsorPage(token, after);
|
||||||
|
const nodes = connection.nodes ?? [];
|
||||||
|
for (const node of nodes) {
|
||||||
|
const sponsor = toSponsorRecord(node);
|
||||||
|
if (sponsor) sponsors.push(sponsor);
|
||||||
|
}
|
||||||
|
if (!connection.pageInfo?.hasNextPage) break;
|
||||||
|
after = connection.pageInfo.endCursor ?? null;
|
||||||
|
if (!after) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sponsors.sort((a, b) => a.name.localeCompare(b.name, "en"));
|
||||||
|
|
||||||
|
const output = {
|
||||||
|
title: "GitHub Sponsors",
|
||||||
|
intro: "Supporters who help keep Open Free Books free and open for learners everywhere.",
|
||||||
|
profile_url: `https://github.com/sponsors/${SPONSORABLE_LOGIN}`,
|
||||||
|
fetched_at: new Date().toISOString(),
|
||||||
|
sponsors,
|
||||||
|
};
|
||||||
|
|
||||||
|
await mkdir(dirname(OUTPUT_PATH), { recursive: true });
|
||||||
|
await writeFile(OUTPUT_PATH, `${JSON.stringify(output, null, 2)}\n`, "utf8");
|
||||||
|
console.log(`Wrote ${OUTPUT_PATH} with ${sponsors.length} sponsor(s).`);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main();
|
||||||
|
|
@ -4,40 +4,40 @@
|
||||||
<title>Open Free Books</title>
|
<title>Open Free Books</title>
|
||||||
<link>https://openfreebooks.org/</link>
|
<link>https://openfreebooks.org/</link>
|
||||||
<description>Recent updates to Open Free Books pages and live chapters.</description>
|
<description>Recent updates to Open Free Books pages and live chapters.</description>
|
||||||
<lastBuildDate>Thu, 21 May 2026 17:43:39 GMT</lastBuildDate>
|
<lastBuildDate>Thu, 21 May 2026 17:54:08 GMT</lastBuildDate>
|
||||||
<item>
|
|
||||||
<title>Integer foundations</title>
|
|
||||||
<link>https://openfreebooks.org/math/integer-foundations/</link>
|
|
||||||
<guid isPermaLink="true">https://openfreebooks.org/math/integer-foundations/</guid>
|
|
||||||
<pubDate>Thu, 21 May 2026 17:43:39 GMT</pubDate>
|
|
||||||
<description>Model directed magnitude on number lines; use the zero principle and tiles to add and subtract integers, and see subtraction as adding an opposite.</description>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<title>Integer arithmetic</title>
|
<title>Integer arithmetic</title>
|
||||||
<link>https://openfreebooks.org/math/integer-arithmetic/</link>
|
<link>https://openfreebooks.org/math/integer-arithmetic/</link>
|
||||||
<guid isPermaLink="true">https://openfreebooks.org/math/integer-arithmetic/</guid>
|
<guid isPermaLink="true">https://openfreebooks.org/math/integer-arithmetic/</guid>
|
||||||
<pubDate>Thu, 21 May 2026 17:43:39 GMT</pubDate>
|
<pubDate>Thu, 21 May 2026 17:54:08 GMT</pubDate>
|
||||||
<description>Multiply and divide integers from models to symbolic rules; apply order of operations with signed numbers in multi-step expressions.</description>
|
<description>Multiply and divide integers from models to symbolic rules; apply order of operations with signed numbers in multi-step expressions.</description>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<title>Integer foundations</title>
|
||||||
|
<link>https://openfreebooks.org/math/integer-foundations/</link>
|
||||||
|
<guid isPermaLink="true">https://openfreebooks.org/math/integer-foundations/</guid>
|
||||||
|
<pubDate>Thu, 21 May 2026 17:54:08 GMT</pubDate>
|
||||||
|
<description>Model directed magnitude on number lines; use the zero principle and tiles to add and subtract integers, and see subtraction as adding an opposite.</description>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<title>Percentage applications</title>
|
<title>Percentage applications</title>
|
||||||
<link>https://openfreebooks.org/math/percentage-applications/</link>
|
<link>https://openfreebooks.org/math/percentage-applications/</link>
|
||||||
<guid isPermaLink="true">https://openfreebooks.org/math/percentage-applications/</guid>
|
<guid isPermaLink="true">https://openfreebooks.org/math/percentage-applications/</guid>
|
||||||
<pubDate>Thu, 21 May 2026 17:43:39 GMT</pubDate>
|
<pubDate>Thu, 21 May 2026 17:54:08 GMT</pubDate>
|
||||||
<description>Relate fractions and decimals to base-100 ratios; calculate percent increase and decrease in financial and real-world contexts.</description>
|
<description>Relate fractions and decimals to base-100 ratios; calculate percent increase and decrease in financial and real-world contexts.</description>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<title>Fractions and decimals</title>
|
<title>Fractions and decimals</title>
|
||||||
<link>https://openfreebooks.org/math/rational-number-operations/</link>
|
<link>https://openfreebooks.org/math/rational-number-operations/</link>
|
||||||
<guid isPermaLink="true">https://openfreebooks.org/math/rational-number-operations/</guid>
|
<guid isPermaLink="true">https://openfreebooks.org/math/rational-number-operations/</guid>
|
||||||
<pubDate>Thu, 21 May 2026 17:43:39 GMT</pubDate>
|
<pubDate>Thu, 21 May 2026 17:54:08 GMT</pubDate>
|
||||||
<description>Convert between fractions, terminating decimals, and repeating decimals; add, subtract, multiply, and divide rational numbers and mixed numbers.</description>
|
<description>Convert between fractions, terminating decimals, and repeating decimals; add, subtract, multiply, and divide rational numbers and mixed numbers.</description>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<title>Ratios & rates foundations</title>
|
<title>Ratios & rates foundations</title>
|
||||||
<link>https://openfreebooks.org/math/ratios-and-rates-foundation/</link>
|
<link>https://openfreebooks.org/math/ratios-and-rates-foundation/</link>
|
||||||
<guid isPermaLink="true">https://openfreebooks.org/math/ratios-and-rates-foundation/</guid>
|
<guid isPermaLink="true">https://openfreebooks.org/math/ratios-and-rates-foundation/</guid>
|
||||||
<pubDate>Thu, 21 May 2026 17:43:39 GMT</pubDate>
|
<pubDate>Thu, 21 May 2026 17:54:08 GMT</pubDate>
|
||||||
<description>Formulate part-to-part and part-to-whole ratios, find equivalent ratios, compute unit rates, and graph proportional relationships.</description>
|
<description>Formulate part-to-part and part-to-whole ratios, find equivalent ratios, compute unit rates, and graph proportional relationships.</description>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
|
|
||||||
|
|
@ -86,11 +86,11 @@
|
||||||
</url>
|
</url>
|
||||||
<url>
|
<url>
|
||||||
<loc>https://openfreebooks.org/math/integer-arithmetic/</loc>
|
<loc>https://openfreebooks.org/math/integer-arithmetic/</loc>
|
||||||
<lastmod>2026-05-21T17:43:39.596Z</lastmod>
|
<lastmod>2026-05-21T17:54:08.000Z</lastmod>
|
||||||
</url>
|
</url>
|
||||||
<url>
|
<url>
|
||||||
<loc>https://openfreebooks.org/math/integer-foundations/</loc>
|
<loc>https://openfreebooks.org/math/integer-foundations/</loc>
|
||||||
<lastmod>2026-05-21T17:43:39.989Z</lastmod>
|
<lastmod>2026-05-21T17:54:08.000Z</lastmod>
|
||||||
</url>
|
</url>
|
||||||
<url>
|
<url>
|
||||||
<loc>https://openfreebooks.org/math/introduction-trigonometry/</loc>
|
<loc>https://openfreebooks.org/math/introduction-trigonometry/</loc>
|
||||||
|
|
@ -130,7 +130,7 @@
|
||||||
</url>
|
</url>
|
||||||
<url>
|
<url>
|
||||||
<loc>https://openfreebooks.org/math/percentage-applications/</loc>
|
<loc>https://openfreebooks.org/math/percentage-applications/</loc>
|
||||||
<lastmod>2026-05-21T17:43:39.595Z</lastmod>
|
<lastmod>2026-05-21T17:54:08.000Z</lastmod>
|
||||||
</url>
|
</url>
|
||||||
<url>
|
<url>
|
||||||
<loc>https://openfreebooks.org/math/permutations-combinations-probability/</loc>
|
<loc>https://openfreebooks.org/math/permutations-combinations-probability/</loc>
|
||||||
|
|
@ -154,11 +154,11 @@
|
||||||
</url>
|
</url>
|
||||||
<url>
|
<url>
|
||||||
<loc>https://openfreebooks.org/math/rational-number-operations/</loc>
|
<loc>https://openfreebooks.org/math/rational-number-operations/</loc>
|
||||||
<lastmod>2026-05-21T17:43:39.472Z</lastmod>
|
<lastmod>2026-05-21T17:54:08.000Z</lastmod>
|
||||||
</url>
|
</url>
|
||||||
<url>
|
<url>
|
||||||
<loc>https://openfreebooks.org/math/ratios-and-rates-foundation/</loc>
|
<loc>https://openfreebooks.org/math/ratios-and-rates-foundation/</loc>
|
||||||
<lastmod>2026-05-21T17:43:39.210Z</lastmod>
|
<lastmod>2026-05-21T17:54:08.000Z</lastmod>
|
||||||
</url>
|
</url>
|
||||||
<url>
|
<url>
|
||||||
<loc>https://openfreebooks.org/math/sequences-series/</loc>
|
<loc>https://openfreebooks.org/math/sequences-series/</loc>
|
||||||
|
|
|
||||||
|
|
@ -345,6 +345,28 @@ h3 {
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sponsors-intro {
|
||||||
|
max-width: 680px;
|
||||||
|
margin: -10px 0 20px;
|
||||||
|
color: var(--soft-ink);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sponsors-cta {
|
||||||
|
margin: 12px 0 0;
|
||||||
|
color: var(--soft-ink);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sponsors-cta a {
|
||||||
|
color: var(--accent);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sponsors-cta a:hover,
|
||||||
|
.sponsors-cta a:focus-visible {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
.tree-cta {
|
.tree-cta {
|
||||||
min-height: clamp(680px, 92vh, 980px);
|
min-height: clamp(680px, 92vh, 980px);
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,30 @@
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.contributing-page__thanks {
|
||||||
|
max-width: var(--prose-width);
|
||||||
|
margin: 0 0 24px;
|
||||||
|
color: var(--soft-ink);
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.7;
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--accent);
|
||||||
|
font-weight: 600;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover,
|
||||||
|
a:focus-visible {
|
||||||
|
text-decoration: underline;
|
||||||
|
text-underline-offset: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.contributing-page__lead {
|
.contributing-page__lead {
|
||||||
margin: 0 0 36px;
|
margin: 0 0 36px;
|
||||||
max-width: var(--prose-width);
|
max-width: var(--prose-width);
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,11 @@
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<section class="contributing-page">
|
<section class="contributing-page">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
{% if page.content %}
|
||||||
|
<div class="contributing-page__thanks">{{ page.content | safe }}</div>
|
||||||
|
{% endif %}
|
||||||
{% include "partials/contributing-content.html" %}
|
{% include "partials/contributing-content.html" %}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
{% include "partials/sponsors-section.html" %}
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
|
||||||
|
|
@ -13,4 +13,5 @@
|
||||||
{% include "partials/credits-content.html" %}
|
{% include "partials/credits-content.html" %}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
{% include "partials/sponsors-section.html" %}
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,8 @@
|
||||||
|
|
||||||
{% include "partials/community-section.html" %}
|
{% include "partials/community-section.html" %}
|
||||||
|
|
||||||
|
{% include "partials/sponsors-section.html" %}
|
||||||
|
|
||||||
<section id="browse-by-subject">
|
<section id="browse-by-subject">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<p class="section-kicker">Catalog</p>
|
<p class="section-kicker">Catalog</p>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
{% set credits = load_data(path="data/credits.json", format="json") %}
|
{% set credits = load_data(path="data/credits.json", format="json") %}
|
||||||
|
{% set sponsors_data = load_data(path="data/github-sponsors.json", format="json") %}
|
||||||
{% set libraries = credits.libraries | sort(attribute="name") %}
|
{% set libraries = credits.libraries | sort(attribute="name") %}
|
||||||
|
|
||||||
<div class="credits-prose">
|
<div class="credits-prose">
|
||||||
|
|
@ -7,6 +8,10 @@
|
||||||
{{ credits.contributors_note }}
|
{{ credits.contributors_note }}
|
||||||
<a href="{{ get_url(path='/') | safe }}#contributors">View contributors</a>.
|
<a href="{{ get_url(path='/') | safe }}#contributors">View contributors</a>.
|
||||||
</p>
|
</p>
|
||||||
|
<p class="credits-contributors-note">
|
||||||
|
Special thanks to our GitHub Sponsors for helping keep this project free and open.
|
||||||
|
<a href="{{ sponsors_data.profile_url | safe }}" rel="noopener noreferrer">Sponsor Open Free Books</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
<section class="credits-block" aria-labelledby="credits-project-heading">
|
<section class="credits-block" aria-labelledby="credits-project-heading">
|
||||||
<h2 id="credits-project-heading" class="credits-section-title">This project</h2>
|
<h2 id="credits-project-heading" class="credits-section-title">This project</h2>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
{% set sponsors_data = load_data(path="data/github-sponsors.json", format="json") %}
|
||||||
|
|
||||||
|
<section id="github-sponsors">
|
||||||
|
<div class="container">
|
||||||
|
<p class="section-kicker">Support</p>
|
||||||
|
<h2 class="section-title">{{ sponsors_data.title }}</h2>
|
||||||
|
<p class="sponsors-intro">{{ sponsors_data.intro }}</p>
|
||||||
|
|
||||||
|
{% if sponsors_data.sponsors and sponsors_data.sponsors | length > 0 %}
|
||||||
|
<ul class="contributors-avatar-grid sponsors-avatar-grid" role="list" data-scroll-reveal>
|
||||||
|
{% for sponsor in sponsors_data.sponsors %}
|
||||||
|
<li class="contributors-avatar-item" data-scroll-reveal-card>
|
||||||
|
<a
|
||||||
|
href="{{ sponsor.url | safe }}"
|
||||||
|
class="contributor-avatar-btn"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
aria-label="GitHub sponsor {{ sponsor.name }}"
|
||||||
|
title="{{ sponsor.name }}"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
class="contributor-avatar-img"
|
||||||
|
src="{{ sponsor.avatar | safe }}"
|
||||||
|
alt=""
|
||||||
|
width="48"
|
||||||
|
height="48"
|
||||||
|
loading="lazy"
|
||||||
|
decoding="async"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
<p class="sponsors-cta">
|
||||||
|
<a href="{{ sponsors_data.profile_url | safe }}" rel="noopener noreferrer">Thank you to all sponsors</a>
|
||||||
|
</p>
|
||||||
|
{% else %}
|
||||||
|
<p class="sponsors-cta">
|
||||||
|
No public sponsors listed yet. <a href="{{ sponsors_data.profile_url | safe }}" rel="noopener noreferrer">Sponsor on GitHub</a>.
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue