Skip to content

Lots - #344

Merged
gregv merged 25 commits into
mainfrom
develop
Aug 16, 2026
Merged

Lots#344
gregv merged 25 commits into
mainfrom
develop

Conversation

@gregv

@gregv gregv commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

No description provided.

gregv and others added 25 commits July 23, 2026 08:56
Feedback: visitors couldn't easily find a project's GitHub repo and its
Issues. "Code & Tasks" was a collapsed accordion at the very bottom, showed
static links only, and disappeared entirely when the problem statement's
github field was empty — which is most hackathon-built projects, since team
repos were only ever written to the team doc.

- Code & Tasks is now an always-visible section directly after the project
  description (unique id per problem statement; header shows an "N repos ↓"
  anchor tag)
- Repo list merges problem_statement.github with repos from the hackathon
  teams that built the project (enriched event fetch; team.problem_statements
  linkage preferred, nonprofit fallback only for teams without it); deduped
  by link, team repos carry "Built by {team} ({event})" attribution
- Live issue data per repo (open/closed chips + top 5 open issue titles)
  fetched lazily through the public /api/github/issues proxy — fire-once
  IntersectionObserver, batched Promise.all, single setState, errors
  swallowed so static links always render; zero open issues shows the
  "write the tickets like a PM" nudge
- No repos at all → "Where's the code?" card linking the event page(s) and
  the project's Slack channel instead of hiding the section
- Onboarding: new "Anatomy of a project page" walkthrough (problem → code →
  plan → people) in Using the Site; /projects copy and the join-a-project
  FAQ updated to match the new UI

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The old section rendered the event location + type as the heading (a street
address), rainbow-era typography, and a blue MUI DevPost button — and its
teams list was dead code: the teams state feeding EventTeams was never
populated, so visitors never saw a single team.

- Event cards now lead with event.title, a quiet Past/Upcoming tag, a
  compact date range (parseLocalDate), location + description as muted
  meta, and constraint tags ("Teams of 2–5", "Max 3 teams per project")
- Ghost Event page / DevPost buttons replace the blue contained button
- New read-only teams list (team name, member first names, "Team page →"
  link) fed by teamsByEvent from the same enriched-event memo that derives
  team repos — visible to everyone, no login gate
- Removed the dead interactive join/leave plumbing from ProblemStatement
  (teams/userDetails state, per-user fetch effect, useTeams handlers);
  event-teams.js and event-team.js are now orphaned — team joining lives
  on the event page / manageteam flow

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replaces the full-width outlined uppercase MUI buttons with calm hairline
rows: navy kind icon, sentence-case document name, a kind tag
(GitHub / Slides / Document / Video / Link), and an open-in-new indicator.
Google Slides links (docs.google.com/presentation) are now classified as
Slides instead of Document. Video references keep their inline
VideoDisplay embed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…sks-discoverability

Project pages: always-visible Code & Tasks with team repos + live Issues; onboarding anatomy walkthrough
- New shared catalog src/lib/projectStatus.js: single source of truth for
  the five ladder stages (concept → hackathon → post-hackathon →
  production → maintenance) plus the new off-ramp "paused" status, with
  labels, short blurbs, and full descriptions.
- ProjectProgress rewritten as a refined stepper rail (done/current/
  upcoming nodes, hairline connectors) with a visible one-line explanation
  of the current stage — replaces the cryptic "concept hack post-hack
  prod maint" chips and their Heroku-era tooltip copy. Paused mutes the
  rail and explains that work is on hold.
- ProblemStatement: paused projects show a quiet "Paused" tag and stop
  recruiting (help toggle hidden except for existing helpers, mirroring
  production); maintenance now shows "Live" + "Welcomes Help" instead of
  reading as unfinished.
- Projects list: Maintenance/Paused filter chips, paused sinks in
  relevance/needs-help sorts, never featured, card footer says "On hold".
- Onboarding ladder now renders from the same catalog + paused footnote.
- Admin problems: status free-text field replaced with a Select of
  canonical statuses (legacy values preserved), unified chip colors.
- Project page SEO meta uses the human status label.
- Removed orphaned duplicate project-progress.js and unused styles.js.

No backend change needed: status is stored as a free-form string and
already passes through create/update.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…paused-redesign

Add "paused" project status + redesign the project status ladder
…he canonical profile API

Ships the shareable public portfolio: PortfolioTab editor (headline/bio,
slug claim, custom links, bio video upload, privacy checklist) and the
public-facing PublicProfile page (hero, about, featured hackathon teams,
GitHub contributions, certificate wall, badges, praises) served from two
routes (vanity /u/<slug> and legacy /profile/<userid>) that both
server-render through a shared portfolioPage/portfolioMeta helper so
unfurls (og:image ladder) stay correct.

Cuts the frontend over from /api/messages/profile* to the canonical
/api/users/* stack (use-profile-api.js, use-public-profile.js,
use-privacy-settings.js) and deletes the dead /myprofile mock page and
its MyProfile/* components.

Also fixes review findings from this cutover:
- GitHubStatsSection hid its whole body under an already-rendered
  heading whenever the backend attached a legitimately-empty
  github_history array (e.g. a new user with a GitHub username but no
  recorded contributions yet). It now shows a "No public GitHub
  activity yet." message instead of rendering nothing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Public portfolio (/u/<slug>, /profile/<userid>) + profile API cutover
[Profile fixes] Better UX to not have giant heart banner
…efinedStyles

Moves the civic-editorial sx constants out of mentor-application.js (the
canonical refined form) into a shared module so judge/sponsor/volunteer
applications can reuse them instead of duplicating ~270 lines each.
No visual or behavioral change to the mentor form.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…lications

Brings the three remaining application forms up to the mentor-application
pattern: RefinedRoot shell, editorial masthead (Eyebrow + Fraunces h1 +
stat cards + side image card), refined stepper, shared field/alert/button
sx from ApplicationForm/refinedStyles, calm .ohx-card frames, refined
event-ended and success states.

Presentation-only: form state, validation, submit payloads, reCAPTCHA,
form persistence, passcode unlock (judge), GA tracking, auth wiring, and
all SEO meta/structured data are unchanged. Check-in QR blocks are now
gated on Boolean(volunteerId) && isSelected like mentor (the component
already self-gated; this just removes the empty card for pending
applicants). Step navigation scrolls to a stepContentRef so it lands on
the fields instead of the taller masthead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…le in CLAUDE.md

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Video: new reusable ApplicationForm/IntroVideoField — controlled URL field
(upload via the portfolio bio-video signed-URL mint, never the profile
finalize; or a YouTube/Vimeo/Loom link). Required on the judge application
(formData.introductionVideoUrl, validated in step 2, prefilled from
previous submissions, GA-tracked, shown as a link in admin review).
Designed to drop into mentor/hacker forms later.

Spacing: FormPersistenceControls' legacy mt:10 stacked with the refined
section's clamp(100px,12vh,148px) top padding, pushing mastheads ~250px
down. Controls now render beside the form (sx={{mt:0}} via new sx prop)
and all four refined application pages share formSectionStyle
(clamp(88px,9vh,108px)) from refinedStyles.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
"4 steps / 4 score criteria / Manual review" described the application
form. Judges landing from search (top term: hackathon judge
opportunities) are deciding whether to commit, so the cards now answer
time, workload, and credibility: 4–6 hrs total commitment / 8–10
projects to score / Since 2013 — all values already claimed on the
judge pillar and judging-criteria pages.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… forms)

FormPersistenceControls moves beside the form (sx mt:0) and both
sections use the shared formSectionStyle instead of the stacked
mt:10 + clamp(100px,12vh,148px) that pushed the masthead down.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Same Select + XS-4XL options as the hacker form's
LocationDemographicsStep, in the Additional Details step. Flows through
the existing ...formData submit spread (no backend change; shirtSize is
already in the public-volunteer denylist) and is prefilled when editing
a previous submission. Shown in admin review (ApplicationReviewCard
volunteer additionalFields + labelMap); the admin edit dialogs already
supported the field.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Volunteer's Next/Back still scrolled formRef (the box wrapping the whole
masthead → page top); mentor/judge/sponsor each carried a copy-pasted
rAF + scrollIntoView block. Extracted a shared scrollToStepContent(ref)
(ApplicationForm/stepScroll.js) used by all four: rAF-deferred so the
new step's DOM is committed, moves focus to the step container
(tabIndex=-1) so keyboard/screen-reader users follow the step change,
and respects prefers-reduced-motion. Hacker already had equivalent
ID-based helpers and is unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tion-forms

Refined UX for judge/sponsor/volunteer applications + judge intro video + spacing fixes
Judging at an in-person event happens only in the room, but the form
soft-warned ('remote judging is possible… we'll discuss logistics') and
let remote applications through. Now, when the event location is
physical (new isVirtualEvent() helper, same heuristic as the volunteer
form), validateAvailability blocks inPerson !== Yes and
canAttendJudging === No on both step-Next and submit, and the
availability step shows blocking alerts that route the applicant to the
mentor application (mentors can join virtually) or online events
instead of a dead end. Partial judging-window attendance stays allowed;
virtual events keep the previous soft-warning behavior. Also collapses
four inline ['Virtual','Global','Online'] location checks into the
helper (adding the 'remote' keyword for volunteer-form parity).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…30 PM

New constraints.judge_judging_{start,end}_time (HH:MM), editable in the
admin Judges section beside the arrival time (with an inverted-window
warning). The judge application derives every judging-window mention —
schedule alert, 'For this event' panel, commitment question, and the
physical-event blocking error — from getJudgingWindow(eventData),
falling back to the previous 3:00/5:30 PM when unset. Times render
through formatTime12h, which now also fixes the venue arrival time
displaying raw 24-hour ('14:00' → '2:00 PM').

Backend companion (branch feature/judge-judging-window): validators.py
accepts the new keys via a shared JUDGE_TIME_CONSTRAINT_KEYS loop.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tion-forms

Feature/refined application forms
The site had four competing type systems and a global html{font-size:12px}
that rendered every rem-based size at 75% of its authored value (12px body
text, 10.5px buttons, 9px captions in MUI; h1 fell back to monospace; the
configured Inter/Space Grotesk body fonts were never actually loaded).

Single source of truth:
- src/styles/fonts.js loads Fraunces + Hanken Grotesk via next/font
  (self-hosted, preloaded, size-adjusted fallbacks); _document.js puts the
  --font-body/--font-display variables on <Html> so they reach MUI portals.
  All JS imports FONT_BODY/FONT_DISPLAY/FONT_MONO; ~30 files that hardcoded
  font stacks now use the tokens (next/font hashes family names, so a
  hardcoded 'Fraunces' literal silently renders a fallback).
- assets/theme.js: body + all heading variants use FONT_BODY (kills the
  Montserrat-monospace h1 and never-loaded Space Grotesk refs).
- RefinedFonts is a deprecated null stub; the /volunteer/track useEffect
  font hack and the per-page Google Fonts links are gone (zero
  fonts.googleapis.com requests).

Root fix (12px -> 100%):
- Legacy CSS (authored for a 10px root) frozen at its current rendered look
  in px (old rem x12); dead CSS deleted (messages-grid.css, sponsors/profile/
  nonprofits styled modules, .button--filter/.headline/.ohack-nonprofit-*
  blocks). refined.js display clamps/eyebrow/lead/btn/tag frozen likewise.
- With the root at 100%, all MUI internals and every hand-written rem font
  size (authored for a 16px root) now render at their intended size.

Application forms (judge readability audit that surfaced all this):
- refinedFormTheme (px variants, Hanken) wraps all five application forms;
  formProseSx caps prose measure at ~70ch; the judge "What good judging
  looks like" panel uses ink (not muted) for primary copy; all form rem
  fontSizes converted to px.

Guardrails:
- src/styles/__tests__/typography.test.js locks the 100% root, zero rem in
  src/styles CSS, token values, and theme fontFamilies.
- New eslint flat config (repo had no linting) bans font-family literals
  outside fonts.js; npm run lint added.
- CLAUDE.md rewritten for the new contract + directory-scoped CLAUDE.md
  files in src/styles and src/components/design with opportunistic-cleanup
  rules for the remaining legacy references.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Central typography system: next/font tokens, 16px root fix, lint/test guardrails
@vercel

vercel Bot commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
frontend-ohack-dev Ready Ready Preview Aug 16, 2026 3:24am

Request Review

@gregv
gregv merged commit ac1cad1 into main Aug 16, 2026
3 checks passed
const videoIconLink = ["youtube.com", "vimeo.com"];
if (videoIconText.some((text) => name.toLowerCase().includes(text)) || videoIconLink.some((text) => link.includes(text))) {
return <SmartDisplayIcon />;
if (l.includes("github.com")) return { Icon: GitHubIcon, kind: "GitHub" };
if (l.includes("github.com")) return { Icon: GitHubIcon, kind: "GitHub" };
if (
l.endsWith(".pptx") ||
l.includes("slides.google.com") ||
}
if (
[".pdf", ".doc", ".docx"].some((ext) => l.endsWith(ext)) ||
l.includes("docs.google.com")
}
const isVideoUrl = (url) =>
url &&
(url.includes("youtube.com") ||
url &&
(url.includes("youtube.com") ||
url.includes("youtu.be") ||
url.includes("vimeo.com") ||
(url.includes("youtube.com") ||
url.includes("youtu.be") ||
url.includes("vimeo.com") ||
url.includes("loom.com") ||
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.

2 participants