Skip to content

docs: add sponsors page#456

Open
jdx wants to merge 1 commit into
mainfrom
codex/add-sponsors-docs-page
Open

docs: add sponsors page#456
jdx wants to merge 1 commit into
mainfrom
codex/add-sponsors-docs-page

Conversation

@jdx
Copy link
Copy Markdown
Collaborator

@jdx jdx commented May 31, 2026

Summary

Validation

  • mise x node@22 -- npm run docs:build

Note

Low Risk
Documentation-only VitePress page with client-side fetch; no product runtime or security-sensitive code paths.

Overview
Adds a Sponsors docs page and links it from the Resources sidebar.

The new page loads sponsor data at runtime from https://en.dev/sponsors.json, groups paid sponsors by tier (Anchor through Backer), shows uncategorized and infrastructure partners, and includes loading/error fallbacks plus a link to become a sponsor on en.dev.

Reviewed by Cursor Bugbot for commit 67393b3. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • New Features

    • Added a dedicated Sponsors page displaying sponsor and infrastructure partner information.
  • Documentation

    • Added "Sponsors" link to the Resources section in navigation.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 31, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR introduces a new Sponsors page in the documentation. The sponsors data is fetched from an external API, organized by tier, and displayed as sponsor cards with optional logos and notes. The page handles errors and loading states gracefully. Navigation is updated to include the new Sponsors link in the sidebar Resources section.

Changes

Sponsors Page Feature

Layer / File(s) Summary
Sponsors page: data fetching, rendering, and styling
docs/sponsors.md
Vue component initializes reactive state, fetches sponsor data from en.dev API on mount with error handling, computes tiered sponsor lists and infrastructure partners, renders sponsor card sections for each tier plus "Other Sponsors" and "Infrastructure Partners", and applies CSS styling for grid layout, card appearance, hover effects, and logo sizing.
Sponsors navigation link
docs/.vitepress/config.mts
VitePress sidebar configuration adds a new "Sponsors" link in the Resources section, converting the single "Troubleshooting" entry to an items array containing both "Troubleshooting" and "Sponsors".

Sequence Diagram

sequenceDiagram
  participant Page as Sponsors Page
  participant API as en.dev API
  participant Vue as Vue Renderer
  
  Page->>API: fetch sponsors.json on mount
  alt API Success
    API-->>Page: sponsor data with tiers & infrastructure
    Page->>Page: compute tiered sponsor lists
    Page->>Vue: render tier sections
    Vue-->>Page: sponsor cards (logo, name, note)
  else API Error
    API-->>Page: HTTP error
    Page->>Vue: render error message
  else Loading
    Page->>Vue: render loading state
  end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 A sponsors page hops into view,
Fetching tiers and partners too,
Cards dance in a grid so bright,
Navigation gleams with fresh delight!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'docs: add sponsors page' is directly related to the main changes, which add a new sponsors page to the documentation and link it in the sidebar.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/add-sponsors-docs-page

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 31, 2026

Greptile Summary

Adds a /sponsors docs page that fetches https://en.dev/sponsors.json client-side and renders sponsors grouped by tier, with loading/error fallbacks, and registers the page in the VitePress sidebar.

  • docs/sponsors.md: new Vue-powered VitePress page with onMounted fetch, tier grouping, and scoped CSS styles.
  • docs/.vitepress/config.mts: one-line sidebar entry under the Resources section.

Confidence Score: 5/5

Documentation-only change; no product runtime is affected and the fetch is purely client-side on a docs page.

The two changed files are a trivial sidebar config update and a new static docs page. The fetch target is a first-party domain the project controls, loading/error states are handled, and nothing here touches app logic or sensitive data paths.

No files require special attention.

Important Files Changed

Filename Overview
docs/.vitepress/config.mts Adds a "Sponsors" sidebar entry under the Resources section — a trivial two-line config change with no issues.
docs/sponsors.md New VitePress page that fetches sponsors.json client-side and renders them by tier; loading/error states handled. Sponsor URLs from the external JSON are bound to href without protocol validation, which would allow javascript: URLs if the endpoint were compromised.

Fix All in Claude Code

Reviews (2): Last reviewed commit: "docs: add sponsors page" | Re-trigger Greptile

@jdx jdx force-pushed the codex/add-sponsors-docs-page branch from 96aa4b1 to 67393b3 Compare May 31, 2026 18:31
@jdx jdx changed the title [codex] Add sponsors docs page docs: add sponsors page May 31, 2026
@jdx jdx marked this pull request as ready for review May 31, 2026 18:32
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
docs/sponsors.md (1)

13-21: ⚡ Quick win

Add request timeout/abort to avoid indefinite loading state.

On Line 15, fetch has no timeout. If the request hangs, Line 36 can show “Loading sponsors...” forever. Add AbortController with a short timeout and surface fallback error state.

Also applies to: 36-37

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/sponsors.md` around lines 13 - 21, The fetch call inside onMounted
should use an AbortController with a short timeout so the request can't hang
indefinitely; create an AbortController, start a setTimeout that calls
controller.abort() after the desired timeout, pass controller.signal into
fetch("https://en.dev/sponsors.json", { signal }), and clear the timeout when
the response arrives; in the catch block detect abort errors (or any error) and
set error.value to a sensible fallback message (e.g., "Request timed out" for
aborts or the caught err.message) and ensure feed.value is left empty/undefined
so the UI exits the "Loading sponsors..." state.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/sponsors.md`:
- Around line 41-43: The anchor uses sponsor.url directly (in the v-for
rendering of sponsor-card), which can allow unsafe schemes; add a URL
validation/sanitization step (e.g., implement isValidSponsorUrl or
sanitizeSponsorUrl used when binding :href) that parses sponsor.url and
allowlists only http: and https: (otherwise return a safe fallback like '#' or
null), then bind the sanitized value to :href for the anchor and ensure existing
rel/target attrs remain; apply the same sanitizer wherever sponsor.url is used
(lines rendering the other sponsor anchors).

---

Nitpick comments:
In `@docs/sponsors.md`:
- Around line 13-21: The fetch call inside onMounted should use an
AbortController with a short timeout so the request can't hang indefinitely;
create an AbortController, start a setTimeout that calls controller.abort()
after the desired timeout, pass controller.signal into
fetch("https://en.dev/sponsors.json", { signal }), and clear the timeout when
the response arrives; in the catch block detect abort errors (or any error) and
set error.value to a sensible fallback message (e.g., "Request timed out" for
aborts or the caught err.message) and ensure feed.value is left empty/undefined
so the UI exits the "Loading sponsors..." state.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: aefa7465-56a0-44c5-a15f-5ec8347b0a64

📥 Commits

Reviewing files that changed from the base of the PR and between 534b00f and 67393b3.

📒 Files selected for processing (2)
  • docs/.vitepress/config.mts
  • docs/sponsors.md

Comment thread docs/sponsors.md
Comment on lines +41 to +43
<a v-for="sponsor in tier.sponsors" :key="sponsor.name" class="sponsor-card" :href="sponsor.url" target="_blank" rel="noopener noreferrer">
<img v-if="sponsor.logo" :src="sponsor.logo" :alt="sponsor.name">
<span>{{ sponsor.name }}</span>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Validate external sponsor URLs before binding to href.

On Line 41, Line 51, and Line 60, sponsor.url is used directly from remote JSON. If that feed is ever compromised, javascript:/unexpected schemes could be injected and executed on click. Please allowlist protocols (for example https: and http:) before rendering links.

Suggested fix
 const infrastructureSponsors = computed(() => (feed.value?.infrastructure || []).filter((s) => s.name && s.url));
+
+function isSafeHttpUrl(value) {
+  try {
+    const u = new URL(value);
+    return u.protocol === "https:" || u.protocol === "http:";
+  } catch {
+    return false;
+  }
+}
+
+function sanitizeSponsors(list) {
+  return (list || []).filter((s) => s?.name && isSafeHttpUrl(s?.url));
+}
 
-const paidSponsors = computed(() => (feed.value?.paid || feed.value?.sponsors || []).filter((s) => s.name && s.url));
+const paidSponsors = computed(() => sanitizeSponsors(feed.value?.paid || feed.value?.sponsors));
 const sponsorsByTier = computed(() => tiers.map(([id, label]) => ({ id, label, sponsors: paidSponsors.value.filter((s) => s.tier === id) })));
 const otherSponsors = computed(() => paidSponsors.value.filter((s) => !tiers.some(([id]) => id === s.tier)));
-const infrastructureSponsors = computed(() => (feed.value?.infrastructure || []).filter((s) => s.name && s.url));
+const infrastructureSponsors = computed(() => sanitizeSponsors(feed.value?.infrastructure));

Also applies to: 51-53, 60-62

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 42-42: Images should have alternate text (alt text)

(MD045, no-alt-text)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/sponsors.md` around lines 41 - 43, The anchor uses sponsor.url directly
(in the v-for rendering of sponsor-card), which can allow unsafe schemes; add a
URL validation/sanitization step (e.g., implement isValidSponsorUrl or
sanitizeSponsorUrl used when binding :href) that parses sponsor.url and
allowlists only http: and https: (otherwise return a safe fallback like '#' or
null), then bind the sanitized value to :href for the anchor and ensure existing
rel/target attrs remain; apply the same sanitizer wherever sponsor.url is used
(lines rendering the other sponsor anchors).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant