Skip to content

feat(events): Stripe-style hackathons directory and detail page, animated hero ribbon - #54

Merged
CodeWithEugene merged 27 commits into
mainfrom
feature/stripe-style-hackathons
Sep 28, 2026
Merged

CodeWithEugene merged 27 commits into
mainfrom
feature/stripe-style-hackathons

Conversation

@CodeWithEugene

Copy link
Copy Markdown
Owner

Summary

Three pieces of work, one commit each (plus a docs rule):

1. Hackathons listing (/hackathons), redesigned as a searchable directory

  • Hero: two-tone heading, a staggered wall of live hackathon covers, and Ongoing / Upcoming / Past links.
  • Live stats row: KES escrowed, hackathons open for registration, teams registered, and hackathons completed. All figures are computed from the listing itself.
  • Featured hackathon: chosen automatically as the biggest prize still open for registration, falling back to the biggest one running. It's hidden once filters are applied.
  • Directory:
    • Sidebar facets (status, category, where, prize pool), each showing a live count.
    • A search and sort form that uses GET, so it works without JavaScript.
    • A grid / list toggle, kept in the URL.
  • Phase-aware cards: organizer trust score, a team capacity bar, and a status line ("Registration closes in 3 days", "Building now · ends 7 Oct", "Winners announced").
  • Few results: when a view has few results, the page shows what's coming up next and a newsletter sign-up.
  • Verification section: keeps the listing's SEO copy word for word.

2. Hackathon detail page (/hackathons/[slug]), laid out like a customer story

  • Hero: breadcrumb, then the title, summary and tracks next to a facts card.
  • Sticky rail: prize pool, dates, where, team places and the registration countdown, plus the register / sign in / workspace / closed action.
  • Sections: status timeline, the challenge, roles and rules, an escrow callout for this exact pool, a prize table with winners and first-payout state, key dates, the organizer, the gallery, and "More hackathons".
  • Unchanged: metadata, Event / breadcrumb structured data, the registration POST and the closed-registration banner.

3. Landing hero

  • Ribbon animation: the ribbon now drifts continuously (the band breathes and twists, and a wave runs across the strands). It pauses off-screen and holds still for reduced motion.
  • Header: on the landing page the header is transparent over the hero, so the ribbon runs up behind the nav. It turns solid once the page scrolls.

Docs: CLAUDE.md now forbids AI attribution in commits, PRs and files.

Implementation notes

  • Filtering, sorting, facet counts, stats, the featured pick and status lines live in lib/events/listing.ts as pure functions, with unit tests in tests/unit/hackathon-listing.test.ts.
  • The cached listing read moved to lib/events/listing-data.ts and is shared by both pages. It still uses revalidate: 300 and the existing revalidatePath("/hackathons") calls. The cache key was bumped because the card shape gained maxTeams.
  • Every filter, search, sort and view variant still canonicalizes to /hackathons.
  • No escrow, payout or contract code is touched.
  • Removed: components/patterns/event-card.tsx and components/patterns/key-dates-card.tsx, now unused.

Test plan

  • tsc --noEmit, next lint and Prettier pass on the changed files
  • New unit tests pass (14 in hackathon-listing.test.ts)
  • Checked against a local Postgres seeded with db/seeds:
    • listing in grid and list view, with filters, search, auto-submitting sort, the empty state and suggestions
    • detail pages for a closed hackathon and an open one (signed out)
    • light and dark mode, 1440px and 375px, no horizontal overflow
  • Hero ribbon animates at 60fps in headless Chrome; the header is transparent at the top of the landing page and solid after scrolling

The landing ribbon now drifts continuously: its edges follow slow,
out-of-step sine waves so the band breathes and twists, and a wave runs
across the strands. It pauses off-screen and holds still for reduced
motion; the server still renders the resting pose.

On the landing page the header is transparent while the hero is under
it, and the hero is pulled up beneath it, so the ribbon is no longer
cut off by the navbar. The header turns solid as soon as the page
scrolls.
Rebuilds /hackathons on the landing page's ruled frame:

- hero with a two-tone heading and a staggered wall of live covers,
  plus Ongoing / Upcoming / Past links
- a live stats row computed from the listing itself (KES escrowed,
  open for registration, teams registered, completed)
- a featured hackathon: the biggest prize still open for registration
  (falls back to the biggest one running), hidden once filters apply
- a directory with sidebar facets (status, category, where, prize pool)
  that show live counts, a GET search and sort form that works without
  JavaScript, and a grid / list toggle kept in the URL
- phase-aware cards: organizer trust score, team capacity bar, tags,
  and a status line (registration closes in N days, building now,
  winners announced) instead of a flat "Registration closed"
- suggestions and a newsletter sign-up when a view has few results
- a verification section that keeps the listing's SEO copy word for word

Filtering, sorting, stats and the featured pick live in
lib/events/listing.ts as pure functions over the single cached read,
with unit tests. Every variant still canonicalizes to /hackathons.
Rebuilds /hackathons/[slug] on the shared ruled frame:

- breadcrumb hero with a large title, summary and track links, and a
  facts card (cover, Prize Verified, host, trust score, format)
- a sticky rail of tick-line stats (prize pool, dates, where, team
  places, registration countdown) with the register / sign in /
  workspace / closed action
- long-form sections: status timeline, the challenge, roles, rules,
  an escrow pull-quote for this exact pool, a prize table with winners
  and first-payout state, a key-dates timeline, the organizer and the
  48-hour gallery
- "More hackathons" from the shared listing cache

Metadata, Event/breadcrumb structured data, the registration POST and
the closed-registration banner are unchanged. The listing's cached read
moves to lib/events/listing-data.ts so both pages share it, and the
now-unused KeyDatesCard is removed.
…tions

The hackathons hero wall is now three columns that loop forever: the
outer two drift up, the middle one down. Tiles are smaller (4:5) so
each column shows two or three at once, dealt round-robin from up to
nine hackathons and topped up so no column runs short. Each column is
rendered twice for a seamless loop (the copy hidden from assistive tech
and the keyboard), the window fades at the top and bottom, and the
motion pauses on hover or focus and stops for reduced motion.
The hackathons filter sidebar now behaves like the legal pages' table of
contents: it sticks under the header while the results beside it
scroll, capped to the window height with its own scroll if the open
groups outgrow it. Filter groups start collapsed (Status stays open, and
a group opens when one of its options is in use), so the sidebar is
shorter than the results and actually has room to sit still.
…m the home page

Removes three sections from the landing page: the "Run the whole event
from one dashboard" product card, the "Organizers ghost winners" photo
banner, and the navy open-infrastructure band (money-flow diagram, wave
stats and take-part cards). Their components, the dashboard mock, the
inverse LandingLink variant and all CSS only they used are deleted.
…e page

Removes the "Built for everyone in the room" intro, the "Hire from
verified Proof-of-Work" hiring section (profile showcase and three
feature points) and the closing "Ready to run a hackathon people
trust?" block from the landing page. The organizer and builder blocks
now stand as their own sections with h2 headings, and the escrow-rule
pull quote moves under the builder block. The closing CTA component
stays in use on /hackathons; the hiring showcase CSS is removed.
Privacy, Terms, How Escrow Works, For Organizers and Contribute share
LegalDocument, which now uses a new shared PageHero (kicker bar, large
title, lead) and the landing frame. Sections open on a hairline, the On
This Page rail stays put beside them, and numbered lists show their
numbers again. No copy changes.
The page uses the shared PageHero, the four steps become story cards
with numbered tick lines, and the newsletter banner becomes a tinted
card in the frame. Copy is unchanged. The old how-it-works, hero-action
and sparkle styles and the unused Sparkle component are removed.
… the blog

The header bar now always takes the frame's width, gutter and hairline
side rules, instead of only on pages that use the new layout, so the
lines run unbroken from the navbar down every page. The blog index and
posts move onto the shared PageHero and frame: hairline blog cards, a
wide cover, the On This Page rail, and Keep Reading in a divided
section. Copy is unchanged.
The Trust page uses the shared PageHero (with the simulation-mode
notice), and the prize vaults and ledger entries become divided sections
in the frame with hairline cards and table. Copy and data are unchanged.
The Proof-of-Work profile gets a tinted hero (name, headline, location,
bio, skills, links) with the five verified metrics as tick-line stats,
then Portfolio, Judge Endorsements and Hiring as divided sections. Copy
and data are unchanged.
The organizer page gets a tinted hero (name, location, badges, about,
links) with its hosted / escrowed / joined figures as tick-line stats,
then Payout Performance, Hackathons and Trust History as divided
sections with hairline cards. Copy and data are unchanged.
The two email unsubscribe pages sit on the tinted hero inside the frame,
and the 404 page keeps its illustration and copy inside the frame's side
rules. No copy changes.
The frame (and the header aligned to it) now grows up to 2200px instead
of stopping at 1440px, so wide screens keep narrow side margins.
Document text caps at a readable 1100px line length inside it.
Past 1800px wide, hero titles, statement headings, section and card
titles and headline stats scale with the screen from the size they stop
at below it (no jump), capped about 45% larger. Their width limits scale
too so line breaks keep their shape. Smaller screens are unchanged.
@CodeWithEugene
CodeWithEugene force-pushed the feature/stripe-style-hackathons branch from d862b3e to bbada93 Compare September 28, 2026 13:08
@CodeWithEugene
CodeWithEugene merged commit 6e5923c into main Sep 28, 2026
4 checks passed

This branch was successfully deployed

1 active deployment
Preview — bbada932 Deployed Sep 28, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant