Every repo you've starred on GitHub, on one searchable 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.
Both variables are optional ā the page works with neither.
| Variable | What it does |
|---|---|
GITHUB_TOKEN | Raises GitHub's rate limit from 60 requests/hour to 5,000. Needs no scopes ā this val only reads public data. |
GITHUB_USER | Whose 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.
The theme is a dark class on <html>, which is what Twind's class dark-mode
strategy keys off. Three pieces:
| Where | What 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.ts | The logic: read, apply, toggle, persist to localStorage, and follow the OS while no explicit choice exists. |
frontend/components/ThemeToggle.tsx | The 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.
<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.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.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.Rendering mermaid diagram...
| Path | Type | Purpose |
|---|---|---|
index.ts | http | Hono app: serves the shell + assets, GET /api/stars |
github.ts | script | GitHub REST client, the Star shape, and the blob cache |
frontend/root.tsx | script | HTML shell (Hono JSX); stamps immutable asset URLs |
frontend/index.tsx | script | React entrypoint |
frontend/components/App.tsx | script | Data fetch, filtering, sorting, paging |
frontend/components/ProfileHeader.tsx | script | Avatar, name, bio, counts |
frontend/components/Filters.tsx | script | Search box, sort select, language chips |
frontend/components/RepoCard.tsx | script | One starred repo |
frontend/components/SetupNote.tsx | script | The amber box explaining the rate limit |
frontend/components/StarIcon.tsx | script | Inline SVG star |
frontend/lib/types.ts | script | Client-side mirror of the API shapes |
frontend/lib/format.ts | script | compact(), relative(), language colors |
frontend/lib/theme.ts | script | Theme read/apply/toggle + localStorage |
frontend/components/ThemeToggle.tsx | script | The dark-mode button |
frontend/favicon.svg | file | Icon |
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./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.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.className; the Hono JSX shell uses class.950 shades, no opacity modifiers like bg-black/5. Use
explicit palette colors and inline styles for computed values (the language
dots).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.