GitHub Stars

Every repo you've starred on GitHub, on one searchable page.

Open the page →

Search across names, owners, descriptions and topics. Filter by language. Sort by when you starred it, how many stars the repo has, or name. The header shows whose stars these are; the footer shows where the data came from and how much GitHub API budget is left.

Configuration

Both variables are optional — the page works with neither.

VariableWhat it does
GITHUB_TOKENRaises GitHub's rate limit from 60 requests/hour to 5,000. Needs no scopes — this val only reads public data.
GITHUB_USERWhose stars to show. Defaults to rodrigoalma.

šŸ‘‰ Add GITHUB_TOKEN here: https://www.val.town/x/rodrigoalcaraz/github-stars/environment-variables?key=GITHUB_TOKEN

šŸ‘‰ Add GITHUB_USER here: https://www.val.town/x/rodrigoalcaraz/github-stars/environment-variables?key=GITHUB_USER

You can also view someone else's stars without touching settings: ?user=torvalds. Add ?refresh=1 to bypass the cache.

Dark mode

The theme is a dark class on <html>, which is what Twind's class dark-mode strategy keys off. Three pieces:

WhereWhat it does
frontend/root.tsx (inline bootstrap)Switches Twind from its default media strategy to class, then applies the saved theme (or the OS preference) before first paint — that's what avoids a flash of light theme on a dark screen.
frontend/lib/theme.tsThe logic: read, apply, toggle, persist to localStorage, and follow the OS while no explicit choice exists.
frontend/components/ThemeToggle.tsxThe button. Reads its initial state off <html> so the icon always matches what the bootstrap applied.

Precedence: a saved choice always wins. With nothing saved, the page follows the OS and updates live if the OS flips mid-session.

  • The bootstrap is inline on purpose — a <script type="module"> is deferred, so it would paint light-on-dark first. This is the one place inline script is the right tool; the toggle's logic lives in a real, typed module.
  • color-scheme is set alongside the class so the browser paints scrollbars, form controls, and the canvas before Twind's CSS exists.
  • mode: "silent" in the Twind config because dark on <html> is not a Twind utility and would otherwise warn on every single page load.
  • The config call is guarded on window.twind and tolerates both install and setup, so a blocked CDN can't take the theme down with it. If the toggle ever stops working, this is the line to check — with the config not applied, dark: falls back to the media strategy and the page follows the OS instead.
  • Only color utilities carry dark: variants. Twind enables the variant for all directives, but Tailwind's own dark mode only generates color-related ones — staying on colors keeps the classes portable.

Architecture

Rendering mermaid diagram...

File map

PathTypePurpose
index.tshttpHono app: serves the shell + assets, GET /api/stars
github.tsscriptGitHub REST client, the Star shape, and the blob cache
frontend/root.tsxscriptHTML shell (Hono JSX); stamps immutable asset URLs
frontend/index.tsxscriptReact entrypoint
frontend/components/App.tsxscriptData fetch, filtering, sorting, paging
frontend/components/ProfileHeader.tsxscriptAvatar, name, bio, counts
frontend/components/Filters.tsxscriptSearch box, sort select, language chips
frontend/components/RepoCard.tsxscriptOne starred repo
frontend/components/SetupNote.tsxscriptThe amber box explaining the rate limit
frontend/components/StarIcon.tsxscriptInline SVG star
frontend/lib/types.tsscriptClient-side mirror of the API shapes
frontend/lib/format.tsscriptcompact(), relative(), language colors
frontend/lib/theme.tsscriptTheme read/apply/toggle + localStorage
frontend/components/ThemeToggle.tsxscriptThe dark-mode button
frontend/favicon.svgfileIcon

Notes

  • Two things protect the rate limit. github.ts caches a snapshot in blob storage for 5 minutes, so repeat page views cost zero GitHub requests. When the budget really is gone, /api/stars answers 429 with the ledger and the page renders SetupNote — instructions for making a token — instead of a bare error.
  • Never answer 502 from /api/stars. The CDN replaces an origin 502 with its own HTML error page, so the JSON body never arrives and the client dies on Unexpected token '<'. A missing user is 404, an exhausted limit is 429, a GitHub failure is 500. App.tsx parses the response body itself as a backstop.
  • The server flattens GitHub's payload. github.ts keeps only the fields the page renders, so /api/stars stays small even for someone with 1,000 stars (we walk at most 10 pages of 100).
  • frontend/lib/types.ts mirrors the server shapes by hand rather than importing github.ts — a client module may only import things the browser can fetch, and github.ts pulls in std/blob.
  • Client components use className; the Hono JSX shell uses class.
  • Styling is Twind (Tailwind utility classes, no build step). Twind's theme is Tailwind v2 — no 950 shades, no opacity modifiers like bg-black/5. Use explicit palette colors and inline styles for computed values (the language dots).
  • An unquoted object key containing a space silently blanks the whole page. Vim script: "#199f4b" (no quotes) is accepted in the editor but transpiles to Vim, script: in the emitted JavaScript, which throws at module load. The module graph dies before React mounts, so #root stays empty and nothing reaches the val logs — no error, just a blank page. The fallback text inside #root in root.tsx exists so this shows up as visible text instead. If you ever see it, check the browser console, then check the transpiled output of the module that changed.
  • data-status on the loading/error/empty/count/footer elements, data-repo and data-language on each card, data-rate-limit on the footer's API line, and data-setup="rate-limit" on the amber box — for Playwright.