Selected work 02
Time Tapestry
A calendar that shows the birthdays, events and sky for any date. Save up to five birthdays of your own, privately or shared with everyone.
- Released
- Feb 2025
- Type
- Full stack
- Stack
- React / TypeScript / Supabase / Tailwind / Mantine / Astronomy Engine

Why
I wanted to practise using a calendar to drive an app’s state: pick a date and everything else updates, from birthdays to the sky, with real data plugged in. It was also a good excuse to learn magic link, passwordless sign-in. And I liked the idea of a place where the community’s birthdays get celebrated too.
What it does
- Pick a date to see notable birthdays and three historical events from that day, each linking to Wikipedia.
- Save up to five birthdays with a one-time sign-in link. They’re private unless you choose to share one.
- The Moon’s phase, rise and set, planetary positions, zodiac details and upcoming eclipses for the date.
- Light and dark themes, and it installs as an app.
Hardest part
Sharing a birthday without sharing who it belongs to. The relationship (“Son”, “Friend”) lives in its own table that only its owner can read, and the community sees a view of public birthdays without it. Postgres enforces both, along with the five-birthday limit, so the browser can’t get around them.
What I learned
- Row-level security in Postgres: policies let owners read and delete their own birthdays, and everyone else read only the public ones.
- Magic link sign-in with Supabase Auth and Resend, so saving a birthday doesn’t need a password.
- Astronomy Engine works out the Moon, planets and eclipses in the browser, with rise and set times for New York, so there’s no astronomy API to call.
- Wikimedia’s On This Day feed: the three events with the most linked pages, and birthdays filtered down to people who are still living.
- Zustand stores for the date, theme, sign-in and birthdays, shared across the sidebar and every tab.
Revisited
- Oct 2026: shared birthdays with Supabase and magic link sign-in, dark mode, live astronomy data on every tab, and a Playwright check in CI.