Conversation
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
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
| 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") || |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.