Static site for eustasy — products, open-source index, activity feed. Built with Astro on Bun, deployed to GitHub Pages.
The activity feed, repo grid, and stats are sourced from the GitHub API by
scheduled GitHub Actions workflows that snapshot data into src/data/*.json.
Requires Bun ≥ 1.2.
bun install
bun run dev # http://localhost:4321
bun run build # → dist/
bun run preview # serve dist/ locallysrc/
layouts/SiteLayout.astro # shared head, header, footer, theme toggle
pages/
index.astro # homepage (hero, products, repos, activity, community)
open-source.astro # searchable repo index
styles/ # flexoki, reset, typography, button, badge, card, site
data/
repos.json # all repos — refreshed daily
commits.json # commit + release feed — refreshed every 2h
discussions.json # issue + discussion feed — refreshed every 2h
public/ # favicon, robots.txt, brand marks
scripts/
lib/{github,events}.mjs # shared API helpers
fetch-{repos,commits,discussions}.mjs
.github/workflows/
deploy.yml # push to main → build → Pages
refresh-repos.yml # daily 06:00 UTC
refresh-commits.yml # every 2h on the hour
refresh-discussions.yml # every 2h, 30min offset
_legacy/ # the old PHP site, kept for reference
Three independent fetch scripts pull from the GitHub API and write JSON. Each runs on its own cron (see workflows above) and only commits when the JSON actually changes. They never overwrite with empty results — if the API call fails or returns nothing, the existing snapshot stays.
Needs a GitHub token with default public_repo read scope. Without a token
the scripts log a warning and no-op.
GITHUB_TOKEN=ghp_… bun run fetch:repos
GITHUB_TOKEN=ghp_… bun run fetch:commits
GITHUB_TOKEN=ghp_… bun run fetch:discussions
GITHUB_TOKEN=ghp_… bun run fetch:allEach refresh workflow has a workflow_dispatch trigger:
gh workflow run refresh-repos.yml
gh workflow run refresh-commits.yml
gh workflow run refresh-discussions.ymlThe default GITHUB_TOKEN is sufficient — no extra secrets needed.
| Script | Output | Cadence | Source |
|---|---|---|---|
fetch-repos.mjs |
src/data/repos.json |
daily 06:00 UTC | GraphQL organization.repositories over eustasy and eustasy-archive |
fetch-commits.mjs |
src/data/commits.json |
every 2h, on the hour | REST /orgs/*/events — PushEvent + ReleaseEvent |
fetch-discussions.mjs |
src/data/discussions.json |
every 2h, 30min past | REST /orgs/*/events — IssuesEvent + PullRequestEvent + IssueCommentEvent |
Repos are classified by description prefix (EOL:, DEPRECATED:, ALPHA:)
and GitHub's isArchived flag. Languages map from primaryLanguage to a
small slug taxonomy (css, js, php, python, bash, html, jq,
meta). Repos whose name starts with . are treated as meta unless they're
.ui.
deploy.yml runs on every push to main (including the data-refresh
commits). It runs bun install, bun run build, uploads dist/ as a Pages
artifact, and deploys.
GitHub Pages must be set to Source: GitHub Actions in repo settings.
- Static content (a new page): add
src/pages/whatever.astrousingSiteLayout. - Featured repos on the homepage: edit the
FEATURED_NAMESlist insrc/pages/index.astro. Names must matchnameinrepos.json. - New repo classification rule: edit
classifyStatus/classifyLanginscripts/lib/github.mjs. - New activity event type: extend
fromXcases inscripts/fetch-commits.mjsorscripts/fetch-discussions.mjs.
Flexoki tokens live in src/styles/flexoki.css. The accent colour and
density are global CSS custom properties (--site-accent,
--site-accent-bg, --site-density) defined in src/styles/site.css. The
open-source page overrides the accent to orange via a body[data-screen-label]
selector — easy to mirror for other pages.
Theme toggle persists choice in localStorage under eustasy-theme. The
inline script in SiteLayout.astro runs before paint to avoid a flash.
MIT — see LICENSE.md.