From d25a2bd7b487c88dcf315fd9482b363ec28e7f87 Mon Sep 17 00:00:00 2001 From: Gaurav Shah Date: Fri, 3 Jul 2026 22:06:16 -0700 Subject: [PATCH 1/4] Add site-wide sticky apply banner Promote the applications banner to a sticky announcement bar pinned above the navbar on every page (previously only inside the Join Us hero). - New ApplyBar: slim fixed top bar, renders only while APPLICATION_IS_LIVE - Layout sets --apply-banner-h so the navbar and all page content offset by the bar's height (0 when the bar is hidden) - Navbar top anchored to --apply-banner-h - Remove the now-duplicate inline ApplyNowBanner from JoinUsHero and delete the unused component Co-Authored-By: Claude Opus 4.8 --- src/app/layout.tsx | 16 ++++++++- src/components/layout/ApplyBar.tsx | 49 ++++++++++++++++++++++++++ src/components/layout/Navbar.tsx | 2 +- src/components/sections/JoinUsHero.tsx | 7 ++-- src/components/ui/ApplyNowBanner.tsx | 47 ------------------------ 5 files changed, 67 insertions(+), 54 deletions(-) create mode 100644 src/components/layout/ApplyBar.tsx delete mode 100644 src/components/ui/ApplyNowBanner.tsx diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 7d7a7147..7cec89f0 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,12 +1,15 @@ import type { Metadata } from "next"; +import type { CSSProperties } from "react"; import { Analytics } from "@vercel/analytics/react"; import "./globals.css"; +import { ApplyBar, APPLY_BAR_HEIGHT } from "@/components/layout/ApplyBar"; import Footer from "@/components/layout/Footer"; import MainContent from "@/components/layout/MainContent"; import { NavMenuProvider } from "@/components/layout/NavMenuContext"; import Navbar from "@/components/layout/Navbar"; import ScrollToTopButton from "@/components/layout/ScrollToTopButton"; import { Geist } from "next/font/google"; +import { APPLICATION_IS_LIVE } from "@constants/applications"; import { cn } from "@/lib/utils"; const geist = Geist({ subsets: ["latin"], variable: "--font-sans" }); @@ -23,9 +26,20 @@ export default function RootLayout({ }: Readonly<{ children: React.ReactNode; }>) { + // When applications are live, the sticky ApplyBar occupies the top of the + // viewport; `--apply-banner-h` offsets the navbar (see Navbar) and pushes all + // page content down by exactly the bar's height. + const bannerStyle = APPLICATION_IS_LIVE + ? ({ "--apply-banner-h": APPLY_BAR_HEIGHT } as CSSProperties) + : undefined; + return ( - + + {children} diff --git a/src/components/layout/ApplyBar.tsx b/src/components/layout/ApplyBar.tsx new file mode 100644 index 00000000..7ec73a5a --- /dev/null +++ b/src/components/layout/ApplyBar.tsx @@ -0,0 +1,49 @@ +"use client"; + +import Link from "next/link"; + +import { + APPLICATION_CLOSE_DATETIME, + APPLICATION_IS_LIVE, + APPLICATION_LINK, +} from "@constants/applications"; +import { buttonVariants } from "@/components/ui/button-variants"; + +/** Height of the bar. Kept in sync with `--apply-banner-h` set in the layout. */ +export const APPLY_BAR_HEIGHT = "3rem"; + +/** + * Site-wide sticky announcement bar pinned above the navbar. Renders only while + * applications are open; the layout mirrors this with `--apply-banner-h` so the + * navbar and page content offset by exactly this height (0 when hidden). + */ +export function ApplyBar() { + if (!APPLICATION_IS_LIVE) return null; + + const closeDate = APPLICATION_CLOSE_DATETIME.format("MMMM D, YYYY"); + + return ( +
+

+ + Applications to join Blueprint next term are open, and close{" "} + {closeDate}. + + Applications close {closeDate}. +

+ + + Apply + +
+ ); +} diff --git a/src/components/layout/Navbar.tsx b/src/components/layout/Navbar.tsx index f49ca8f3..54f9522c 100644 --- a/src/components/layout/Navbar.tsx +++ b/src/components/layout/Navbar.tsx @@ -189,7 +189,7 @@ export default function Navbar() { return (
= 1 ? "none" : "auto", diff --git a/src/components/sections/JoinUsHero.tsx b/src/components/sections/JoinUsHero.tsx index e5d8e628..fd5babaf 100644 --- a/src/components/sections/JoinUsHero.tsx +++ b/src/components/sections/JoinUsHero.tsx @@ -2,7 +2,6 @@ import UnderlineToBackground from "@/components/fancy/text/underline-to-background"; import { scrollToElement } from "@/lib/utils"; -import { ApplyNowBanner } from "../ui/ApplyNowBanner"; const SECTION_LINKS: { id: string; label: string }[] = [ { id: "why-join", label: "why join" }, @@ -35,11 +34,9 @@ export function JoinUsHero() {
+ >
- -

); -} \ No newline at end of file +} diff --git a/src/components/ui/ApplyNowBanner.tsx b/src/components/ui/ApplyNowBanner.tsx deleted file mode 100644 index 3610d747..00000000 --- a/src/components/ui/ApplyNowBanner.tsx +++ /dev/null @@ -1,47 +0,0 @@ -"use client"; - -import Link from "next/link"; - -import { - APPLICATION_CLOSE_DATETIME, - APPLICATION_IS_LIVE, - APPLICATION_LINK, -} from "@constants/applications"; -import { buttonVariants } from "@/components/ui/button-variants"; -import { cn } from "@/lib/utils"; - -export interface ApplyNowBannerProps { - className?: string; -} - -export function ApplyNowBanner({ className }: ApplyNowBannerProps) { - if (!APPLICATION_IS_LIVE) return null; - - const closeDate = APPLICATION_CLOSE_DATETIME.format("MMMM D, YYYY"); - - return ( -
-
-

- Applications to join Blueprint next term are open, and close{" "} - {closeDate}. -

- -
- - Apply - -
-
-
- ); -} From 103786a0f59c42b19a3d9796079a4f08d0136b1b Mon Sep 17 00:00:00 2001 From: Gaurav Shah Date: Fri, 3 Jul 2026 22:11:43 -0700 Subject: [PATCH 2/4] Apply bar: 'Apply now' label and taller bar - Button reads "Apply now" - Increase bar height (3rem -> 3.5rem) for more vertical breathing room; --apply-banner-h offset stays in sync Co-Authored-By: Claude Opus 4.8 --- src/components/layout/ApplyBar.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/layout/ApplyBar.tsx b/src/components/layout/ApplyBar.tsx index 7ec73a5a..7a9c4361 100644 --- a/src/components/layout/ApplyBar.tsx +++ b/src/components/layout/ApplyBar.tsx @@ -10,7 +10,7 @@ import { import { buttonVariants } from "@/components/ui/button-variants"; /** Height of the bar. Kept in sync with `--apply-banner-h` set in the layout. */ -export const APPLY_BAR_HEIGHT = "3rem"; +export const APPLY_BAR_HEIGHT = "3.5rem"; /** * Site-wide sticky announcement bar pinned above the navbar. Renders only while @@ -25,7 +25,7 @@ export function ApplyBar() { return (

@@ -42,7 +42,7 @@ export function ApplyBar() { size: "sm", })} shrink-0`} > - Apply + Apply now

); From 01e50e2f454c58c1f169791913b51ee8d6ed9a19 Mon Sep 17 00:00:00 2001 From: Gaurav Shah Date: Fri, 3 Jul 2026 22:12:35 -0700 Subject: [PATCH 3/4] Apply bar: make 'Apply now' a text link Swap the filled button for an inline underlined link so it fits the slim announcement bar. Co-Authored-By: Claude Opus 4.8 --- src/components/layout/ApplyBar.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/components/layout/ApplyBar.tsx b/src/components/layout/ApplyBar.tsx index 7a9c4361..8158e006 100644 --- a/src/components/layout/ApplyBar.tsx +++ b/src/components/layout/ApplyBar.tsx @@ -7,7 +7,6 @@ import { APPLICATION_IS_LIVE, APPLICATION_LINK, } from "@constants/applications"; -import { buttonVariants } from "@/components/ui/button-variants"; /** Height of the bar. Kept in sync with `--apply-banner-h` set in the layout. */ export const APPLY_BAR_HEIGHT = "3.5rem"; @@ -37,10 +36,7 @@ export function ApplyBar() { Apply now From 2c0c85b4c1649358118cb20647804cb13146773e Mon Sep 17 00:00:00 2001 From: Gaurav Shah Date: Fri, 3 Jul 2026 22:31:00 -0700 Subject: [PATCH 4/4] Apply bar: add hairline bottom border Distinguishes the sticky bar from page content beneath it. Co-Authored-By: Claude Opus 4.8 --- src/components/layout/ApplyBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/layout/ApplyBar.tsx b/src/components/layout/ApplyBar.tsx index 8158e006..13411979 100644 --- a/src/components/layout/ApplyBar.tsx +++ b/src/components/layout/ApplyBar.tsx @@ -24,7 +24,7 @@ export function ApplyBar() { return (