Skip to content

Repository files navigation

A statically generated site for WXYC. Built using the frontend framework React, NextJs as a static site generator and TinaCMS as a Git-based content management system. Styled using TailwindCSS, with help from the MUI Joy UI component library on implementing breadcrumbs and Headless UI on implementing dropdown menus. Deployed to Github Pages.

Supports content management for the radio station's blog and for an archive of the radio station's specialty shows and live events. Very much a work in progress!

Visit live site


image

[the development of this site is brought to you by the easily accessible assortment of photos of Adrianne Lenker that live on my desktop]

Live playlist (/playlist)

Public view of the most recent flowsheet entries, refreshing while the tab stays open. Successor to wxyc.info/playlists/recent, which goes dark at the 2026-09-07 tubafrenzy cutover (WXYC/wiki#93).

  • Data source: Backend-Service GET /flowsheet?page=0&limit=50. Distinct from the archive's /flowsheet/range: this endpoint returns one flat entries array plus pagination metadata and the currently on-air DJ, rather than a separate shows array, so there is no grouping step. Contract lives in wxyc-shared/api.yaml. Override the origin at build time with NEXT_PUBLIC_WXYC_API_URL; it defaults to https://api.wxyc.org.
  • Client-side only, for the same reason as the archive: a static export has no SSR and no server to poll from, so the fetch happens in the browser, on an interval, for as long as the tab stays open.
  • Entries are ordered by show_id then play_order, both descending, then id descending — most recent show first, and within a show by the DJ's stated air order rather than the order the endpoint returned them in (insertion order). The endpoint returns rows newest-inserted-first, and a DJ who enters a row after the fact gets a row whose id says "just now" but whose play_order says otherwise; rendering in insertion order strands it in the wrong place. The id tie-break exists because play_order can legitimately collide — the tubafrenzy webhook and the dj-site live-insert path assign it independently with no per-show UNIQUE constraint — matching how Backend's own getEntriesByShow breaks the same tie. See compareEntriesByAirOrderDesc in lib/flowsheetRange.js, shared with the archive page's own play_order rule.
  • A failed poll keeps the last good playlist on screen rather than replacing it with an error: the table is still true, just stale. A "Last updated HH:MM — couldn't refresh" notice and a Retry button appear alongside it so the page is never silently frozen; only a failure on the very first load (nothing to show yet) replaces the page with a full error state.
  • Polling pauses while the tab is hidden — checked both at mount and on every subsequent visibility change, so a tab opened directly in the background never fetches at all until it is actually shown — and catches up with one fetch when it becomes visible again, rather than continuing to poll a tab nobody is looking at. The response is ~51 KB with Cache-Control: no-cache, and a tab left open for a workday would otherwise issue roughly 1,440 requests for ~73 MB.
  • Each poll aborts any still-in-flight one before starting, so a slow earlier response landing after a faster later one cannot overwrite fresher data with stale.

DNS & hosting (do not "fix" the Pages domain warning)

wxyc.org and www.wxyc.org are proxied through Cloudflare (orange-cloud) rather than pointing their DNS records directly at GitHub Pages. Cloudflare forwards the Host header to GitHub Pages as the origin, so the site is still built and served by this repo's Pages deploy exactly as before — Cloudflare just sits in front of it (this is what lets us attach edge Workers to the apex).

Because the public A/AAAA records no longer resolve to GitHub's Pages IPs (they resolve to Cloudflare's edge), repo Settings → Pages will show a warning that the custom domain's DNS does not point at GitHub Pages. This warning is expected and cosmetic — the site works. Do not change the DNS records back to GitHub's IPs, and do not clear the custom-domain field in Settings → Pages (the custom domain lives only there; there is no CNAME file in the repo). Reverting either would break the Cloudflare proxy in front of the apex. If you need to take Cloudflare out of the path, toggle the apex + www records from orange (Proxied) back to gray (DNS only) in the Cloudflare dashboard.

TLS & certificates (do not set SSL/TLS mode to Full (strict))

There are two certificates in front of this site. The edge certificate is Cloudflare's (Google Trust Services) and is what browsers actually see; Cloudflare renews it automatically and it has never been a problem. The origin certificate is the Let's Encrypt certificate GitHub Pages manages for the custom domain, presented to Cloudflare when it fetches from the origin. Since the proxy went in front of the apex the origin certificate is invisible to browsers — read it by connecting to a Pages IP directly rather than to wxyc.org: echo | openssl s_client -servername wxyc.org -connect 185.199.108.153:443 2>/dev/null | openssl x509 -noout -issuer -dates.

The origin certificate's renewal is currently broken. GET /repos/WXYC/website/pages reports https_certificate.state: "bad_authz" — "The ACME authorization is in a bad state. We need to start over." The ACME challenge path is not the cause: /.well-known/acme-challenge/* reaches the Pages origin untouched through the proxy for both wxyc.org and www.wxyc.org, and there are no CAA records on the domain. Only GitHub can clear this state, and the WXYC org is on GitHub Free, whose support form offers no Pages category — so the route is GitHub Community Discussions. Full investigation in #209.

Because of that, the Cloudflare SSL/TLS mode must stay on Full (non-strict), not Full (strict). Full (strict) validates the origin certificate, so when the stuck certificate expires the site returns 526 and goes completely offline; under plain Full, Cloudflare still encrypts to the origin but does not validate it, so an expired origin certificate is harmless. This is what keeps the 2026-09-19 expiry from being an outage. Restore Full (strict) only once https_certificate.state reads approved and a certificate with a new serial is confirmed on the origin. #209's original preflight instruction to use Full (strict) is superseded by this note.

Do not try to fix the certificate by clearing and re-adding the custom domain. This was tested twice — with an immediate re-add, and with a 20-minute gap — and GitHub restored the identical bad_authz record both times, so it does not work at any duration. It is also actively harmful: while the domain is detached, Pages returns 404 for the hostname and GitHub's Fastly layer caches that 404 per path, then keeps serving it well past its own max-age. The only purge available is a new Pages deployment — and since this site normally deploys only when TinaCMS content changes (sometimes a week apart), a poisoned path can stay broken for days. If you must verify something while the domain is detached, probe the origin with a Host: header (curl -k -H 'Host: wxyc.org' https://185.199.108.153/) rather than through Cloudflare, which is what creates the cache entry in the first place.

Two related settings follow from this and should be left alone. Always Use HTTPS is enabled at Cloudflare and is what now serves the http→https redirect, because GitHub's own https_enforced is stuck false and cannot be re-enabled while the certificate is unissued. And www.wxyc.org is redirected to the apex by a Cloudflare Page Rule (www.wxyc.org/*https://wxyc.org/$1, 301) rather than by GitHub's www-to-apex canonicalization, so www no longer touches the Pages origin at all.

Wishlist

  • Setlist component for blog posts
  • Contact form and instagram integrations (implemented in development, need to figure out how to host)
  • Search bar for archive and blog
  • Utilize Tina blocks to make more components of site editable by admin
  • Embed audio player in layout so music can continue as you browse the site

About

Static website for WXYC.org

Resources

Stars

2 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages