Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useEffect } from 'react'
import Seo from '@/components/Seo'
import { SITE_URL } from '@/lib/site'
import dynamic from 'next/dynamic'
import Nav from '@/components/Nav'
import Hero from '@/components/Hero'
import Capabilities from '@/components/Capabilities'
Expand All @@ -11,6 +12,9 @@ import OpenSource from '@/components/OpenSource'
import Partners from '@/components/Partners'
import Footer from '@/components/Footer'

// Client-only: its visibility depends on localStorage and the current date.
const AnnouncementBar = dynamic(() => import('@/components/AnnouncementBar'), { ssr: false })

export default function Home() {
// Set up scroll-reveal observer (mirrors the original HTML script)
useEffect(() => {
Expand All @@ -35,6 +39,7 @@ export default function Home() {
return (
<>
<Seo url={SITE_URL} />
<AnnouncementBar />
<Nav hero />
<Hero />
<hr className="divider" />
Expand Down
6 changes: 4 additions & 2 deletions pages/inference-day.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import Seo from '@/components/Seo'
import Footer from '@/components/Footer'
import Nav from '@/components/Nav'
import { SITE_URL } from '@/lib/site'
import EventNav from '@/components/inference-day/EventNav'
import EventSubNav from '@/components/inference-day/EventSubNav'
import EventHero from '@/components/inference-day/EventHero'
import RegisterSection from '@/components/inference-day/RegisterSection'
import Agenda from '@/components/inference-day/Agenda'
Expand Down Expand Up @@ -54,7 +55,8 @@ export default function InferenceDay() {
</Seo>

<div className="id-page">
<EventNav />
<Nav />
<EventSubNav />
<main>
<EventHero />
<RegisterSection />
Expand Down
57 changes: 57 additions & 0 deletions src/components/AnnouncementBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { useState } from 'react'
import Link from 'next/link'

// Homepage announcement bar for the Inference Day event. Links to the event
// landing page, can be dismissed (remembered per browser), and hides itself once
// the event date has passed so it never needs to be removed by hand.
//
// Rendered client-only (next/dynamic ssr:false in the homepage), so the initial
// visibility is read straight from localStorage/the clock in the useState
// initializer — no effect, and no server/client markup to mismatch.
const EVENT_URL = '/inference-day'
const HIDE_AFTER = new Date('2026-11-06T00:00:00Z') // day after the event
const DISMISS_KEY = 'mp-inference-day-bar'

function shouldShow(): boolean {
if (Date.now() >= HIDE_AFTER.getTime()) return false
try {
return localStorage.getItem(DISMISS_KEY) !== 'dismissed'
} catch {
// private mode / blocked storage — treat as not dismissed
return true
}
}

export default function AnnouncementBar() {
const [show, setShow] = useState(shouldShow)

function dismiss() {
setShow(false)
try {
localStorage.setItem(DISMISS_KEY, 'dismissed')
} catch {
// storage unavailable — nothing to persist
}
}

if (!show) return null

return (
<aside className="announce" aria-label="Inference Day announcement">
<Link href={EVENT_URL} className="announce-link">
<span className="announce-wordmark">Inference Day</span>
<span className="announce-sep" aria-hidden="true" />
<span className="announce-tag">Nov 5 · Virtual · Free</span>
<span className="announce-copy">
Hear where AI infrastructure is going from the engineers building it.
</span>
<span className="announce-cta">Register →</span>
</Link>
<button className="announce-close" onClick={dismiss} aria-label="Dismiss announcement">
<svg width="14" height="14" viewBox="0 0 14 14" aria-hidden="true">
<path d="M1 1l12 12M13 1L1 13" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" />
</svg>
</button>
</aside>
)
}
2 changes: 2 additions & 0 deletions src/components/Nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
<nav className={navClass}>
<div className="wrap">
<Link href="/" className="nav-logo">
<img src="/icon-color.svg" alt="Modelplane" height={32} />

Check warning on line 50 in src/components/Nav.tsx

View workflow job for this annotation

GitHub Actions / build

Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` or a custom image loader to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element
</Link>

<ul className="nav-links">
Expand All @@ -55,6 +55,7 @@
<li><Link href="/blog">Blog</Link></li>
<li><Link href="/manifesto">Manifesto</Link></li>
<li><a href={SLACK_URL} target="_blank" rel="noopener noreferrer">Slack</a></li>
<li><Link href="/inference-day" className="nav-event">Inference Day</Link></li>
<li><a href={GITHUB_URL} target="_blank" rel="noopener noreferrer" aria-label="GitHub"><GithubIcon /></a></li>
<li><a href={GITHUB_URL} className="nav-cta-ghost" target="_blank" rel="noopener noreferrer">★ Star the Project</a></li>
<li><a href="https://docs.modelplane.ai/getting-started/" className="nav-cta">Get started →</a></li>
Expand All @@ -75,6 +76,7 @@
<Link href="/blog" onClick={() => setOpen(false)}>Blog</Link>
<Link href="/manifesto" onClick={() => setOpen(false)}>Manifesto</Link>
<a href={SLACK_URL} target="_blank" rel="noopener noreferrer" onClick={() => setOpen(false)}>Slack</a>
<Link href="/inference-day" className="nav-event" onClick={() => setOpen(false)}>Inference Day</Link>
<a href={GITHUB_URL} target="_blank" rel="noopener noreferrer" aria-label="GitHub" onClick={() => setOpen(false)}><GithubIcon /></a>
<a href={GITHUB_URL} className="nav-cta-mobile" target="_blank" rel="noopener noreferrer" onClick={() => setOpen(false)}>★ Star the Project</a>
<a href="https://docs.modelplane.ai/getting-started/" className="nav-cta-mobile" onClick={() => setOpen(false)}>Get started →</a>
Expand Down
12 changes: 6 additions & 6 deletions src/components/inference-day/EventHero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ export default function EventHero() {
</p>

<EventActions />

<img
src="/inference-day/lockup.png"
alt="Hosted by Modelplane · Sponsored by Upbound"
className="id-hero-lockup"
/>
</div>
</div>

<img
src="/inference-day/lockup.png"
alt="Hosted by Modelplane · Sponsored by Upbound"
className="id-hero-lockup"
/>
</section>
)
}
61 changes: 0 additions & 61 deletions src/components/inference-day/EventNav.tsx

This file was deleted.

20 changes: 20 additions & 0 deletions src/components/inference-day/EventSubNav.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Event sub-nav for the Inference Day landing page. Sits directly below the main
// site <Nav /> and sticks under it, carrying only the on-page jump links plus a
// Register CTA. The "Inference Day" label marks which section of the site you're
// in, since the main nav shows the Modelplane logo. All links are in-page anchors,
// so they stay plain <a> (next/link is for route navigation).
export default function EventSubNav() {
return (
<nav className="id-subnav" aria-label="Inference Day sections">
<div className="id-wrap id-subnav-inner">
<a href="#top" className="id-subnav-label">Inference Day</a>
<div className="id-subnav-links">
<a href="#register">Register</a>
<a href="#agenda">Agenda</a>
<a href="#speakers">Speakers</a>
</div>
<a href="#register" className="btn-primary id-subnav-cta">Register →</a>
</div>
</nav>
)
}
71 changes: 71 additions & 0 deletions src/styles/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -1798,3 +1798,74 @@ a.post-tag:hover { border-color: var(--border-hi); color: var(--text); }
@media (max-width: 560px) {
.post-related .post-grid { grid-template-columns: 1fr 1fr; }
}

/* ── ANNOUNCEMENT BAR (Inference Day, homepage) ── */
.announce {
position: relative;
z-index: 1;
display: flex;
align-items: stretch;
background:
radial-gradient(460px 160px at 14% 50%, rgba(0, 220, 232, 0.16), transparent 72%),
#001C2E;
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
.announce-link {
flex: 1;
min-height: 48px;
display: flex;
align-items: center;
justify-content: center;
gap: 18px;
padding: 9px 56px 9px 24px;
text-decoration: none;
color: #fff;
}
.announce-wordmark {
font-family: var(--display);
font-weight: 600;
font-size: 18px;
letter-spacing: -0.01em;
background: linear-gradient(90deg, #9A5EFC, #00DCE8);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
color: transparent;
white-space: nowrap;
}
.announce-sep { width: 1px; height: 16px; background: rgba(255, 255, 255, 0.18); flex: none; }
.announce-tag {
font-size: 12px; font-weight: 500; letter-spacing: 0.10em; text-transform: uppercase;
color: var(--cyan); white-space: nowrap;
}
.announce-copy { font-size: 14px; color: rgba(255, 255, 255, 0.86); }
.announce-cta {
display: inline-flex; align-items: center; gap: 6px;
background: var(--purple); color: #fff; font-size: 13px; font-weight: 600;
padding: 7px 16px; border-radius: 999px; white-space: nowrap;
transition: background 0.2s;
}
.announce-link:hover .announce-cta { background: linear-gradient(90deg, #9A5EFC, #00DCE8); }
.announce-close {
position: absolute; right: 12px; top: 50%; transform: translateY(-50%);
display: inline-flex; align-items: center; justify-content: center;
width: 32px; height: 32px;
background: none; border: 0; color: rgba(255, 255, 255, 0.55);
cursor: pointer; border-radius: 8px; transition: color 0.2s, background 0.2s;
}
.announce-close:hover { color: #fff; background: rgba(255, 255, 255, 0.08); }

@media (max-width: 760px) {
.announce-copy, .announce-sep { display: none; }
.announce-link { gap: 12px; justify-content: space-between; padding: 8px 48px 8px 16px; }
}
@media (max-width: 420px) {
.announce-tag { display: none; }
}

/* Inference Day event link in the main nav — a subtle cyan accent so the
time-sensitive event stands out next to the standard nav items. */
.nav-links .nav-event,
.nav-dropdown .nav-event { color: var(--cyan); }
.nav-links .nav-event:hover,
.nav-dropdown .nav-event:hover { color: var(--purple-hi); }
Loading
Loading