site: experimental sky hero (will replace with Cursor-style painted backdrop)

This commit is contained in:
Matthew Meszaros
2026-05-26 05:03:23 +00:00
parent 3a4b0b5d55
commit bff49c31c2
3 changed files with 904 additions and 227 deletions
+54 -8
View File
@@ -1,6 +1,12 @@
---
import Wordmark from './Wordmark.astro';
interface Props {
/** Render as transparent over the sky hero, with light text. Becomes solid once scrolled past the hero. */
onSky?: boolean;
}
const { onSky = false } = Astro.props;
const path = Astro.url.pathname;
const nav: { label: string; href: string; match?: string }[] = [
{ label: 'Product', href: '/product/', match: '/product' },
@@ -16,7 +22,14 @@ function active(match?: string) {
return path === match || path.startsWith(match + '/');
}
---
<header class="sticky top-0 z-50 border-b border-border bg-background/80 backdrop-blur supports-[backdrop-filter]:bg-background/65">
<header
id="site-header"
data-on-sky={onSky ? 'true' : 'false'}
class={[
'sticky top-0 z-50 transition-colors duration-200',
onSky ? 'header-on-sky' : 'border-b border-border/70 bg-background/70 backdrop-blur-md supports-[backdrop-filter]:bg-background/55',
].join(' ')}
>
<div class="container-page flex h-14 items-center gap-6">
<Wordmark size="md" />
@@ -25,10 +38,10 @@ function active(match?: string) {
<a
href={n.href}
class={
'h-8 px-3 inline-flex items-center rounded-md text-[13px] transition-colors ' +
'nav-link h-8 px-3 inline-flex items-center rounded-md text-[13px] transition-colors ' +
(active(n.match)
? 'text-foreground bg-surface-2'
: 'text-muted-foreground hover:text-foreground hover:bg-surface-2/60')
? (onSky ? 'is-active' : 'text-foreground bg-surface-2')
: (onSky ? '' : 'text-muted-foreground hover:text-foreground hover:bg-surface-2/60'))
}
>
{n.label}
@@ -39,19 +52,28 @@ function active(match?: string) {
<div class="ml-auto flex items-center gap-2">
<a
href="https://app.warmbly.com/login"
class="hidden sm:inline-flex h-8 px-3 items-center rounded-md text-[13px] text-muted-foreground hover:text-foreground hover:bg-surface-2 transition-colors"
class={
'cta-ghost hidden sm:inline-flex h-8 px-3 items-center rounded-md text-[13px] transition-colors ' +
(onSky ? '' : 'text-muted-foreground hover:text-foreground hover:bg-surface-2')
}
>
Log in
</a>
<a
href="https://app.warmbly.com/register"
class="inline-flex h-8 px-3.5 items-center rounded-md text-[13px] font-medium text-brand-foreground bg-foreground hover:bg-foreground/85 transition-colors"
class={
'cta-primary inline-flex h-8 px-3.5 items-center rounded-md text-[13px] font-medium transition-colors ' +
(onSky ? '' : 'bg-foreground text-background hover:bg-foreground/85')
}
>
Start free
</a>
<button
id="nav-toggle"
class="md:hidden inline-flex h-8 w-8 items-center justify-center rounded-md text-muted-foreground hover:text-foreground hover:bg-surface-2"
class={
'md:hidden inline-flex h-8 w-8 items-center justify-center rounded-md ' +
(onSky ? 'cta-ghost' : 'text-muted-foreground hover:text-foreground hover:bg-surface-2')
}
aria-label="Toggle navigation"
aria-expanded="false"
>
@@ -81,16 +103,40 @@ function active(match?: string) {
))}
<div class="h-px bg-border my-2" />
<a href="https://app.warmbly.com/login" class="h-9 px-2 inline-flex items-center rounded-md text-sm text-muted-foreground hover:text-foreground hover:bg-surface-2">Log in</a>
<a href="https://app.warmbly.com/register" class="h-9 px-2 inline-flex items-center rounded-md text-sm font-medium text-brand-foreground bg-foreground">Start free</a>
<a href="https://app.warmbly.com/register" class="h-9 px-2 inline-flex items-center rounded-md text-sm font-medium text-background bg-foreground">Start free</a>
</div>
</div>
</header>
<script>
// Mobile nav toggle
const toggle = document.getElementById('nav-toggle');
const menu = document.getElementById('mobile-nav');
toggle?.addEventListener('click', () => {
const open = menu?.classList.toggle('hidden') === false;
toggle.setAttribute('aria-expanded', String(open));
});
// If the header is rendered "on sky", flip it to the solid look once
// the hero's bottom sentinel scrolls past the header. Pure IO, no
// scroll listener — cheap.
const header = document.getElementById('site-header');
if (header?.dataset.onSky === 'true') {
const sentinel = document.getElementById('hero-sentinel');
if (sentinel) {
const io = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
header.classList.add('header-on-sky');
header.classList.remove('border-b', 'border-border/70', 'bg-background/70', 'backdrop-blur-md');
} else {
header.classList.remove('header-on-sky');
header.classList.add('border-b', 'border-border/70', 'bg-background/70', 'backdrop-blur-md');
}
},
{ rootMargin: '-56px 0px 0px 0px', threshold: 0 },
);
io.observe(sentinel);
}
}
</script>
+702 -219
View File
File diff suppressed because it is too large Load Diff
+148
View File
@@ -197,6 +197,154 @@ body {
z-index: 0;
}
/* ----------------------------------------------------------------
Auth-style sky — deep blue with cloud blurs, sun glow.
Same palette as web/src/app/auth/layout.tsx but flattened to
pure CSS (no SVG turbulence filters) so it's light to load.
The hero owns its own sky; the bottom of the hero masks to white
so the white page picks up below.
---------------------------------------------------------------- */
.hero-sky {
position: absolute;
inset: 0;
pointer-events: none;
background:
radial-gradient(ellipse 140% 140% at 72% 25%,
#7dd3fc 0%,
#38bdf8 18%,
#0ea5e9 36%,
#0284c7 58%,
#075985 82%
);
}
/* Soft sun glow in the upper-right */
.hero-sun {
position: absolute;
top: 0; right: 0;
width: 900px; height: 900px;
pointer-events: none;
background: radial-gradient(circle,
rgba(253, 230, 138, 0.30) 0%,
rgba(253, 186, 116, 0.10) 32%,
rgba(56, 189, 248, 0.04) 55%,
transparent 70%
);
filter: blur(8px);
transform: translate(20%, -20%);
}
/* Atmospheric upper-left scatter */
.hero-haze {
position: absolute;
inset: 0;
pointer-events: none;
background:
radial-gradient(ellipse 60% 50% at 20% 40%,
rgba(186, 230, 253, 0.18) 0%,
transparent 60%
),
radial-gradient(ellipse 70% 30% at 60% 80%,
rgba(125, 211, 252, 0.20) 0%,
transparent 70%
);
}
/* Bottom of hero fades into pure white — no white wash on top */
.hero-fade {
position: absolute;
inset: 0;
pointer-events: none;
background: linear-gradient(to bottom,
transparent 0%,
transparent 62%,
rgba(255,255,255,0.5) 82%,
#ffffff 100%
);
}
/* Cloud — three soft, blurred white blobs that read as a cumulus.
No SVG filters; just border-radius + blur on layered divs. */
.cloud {
position: absolute;
pointer-events: none;
}
.cloud-back, .cloud-mid, .cloud-front {
position: absolute;
border-radius: 50% 50% 40% 40%;
filter: blur(22px);
}
.cloud-back { background: rgba(255, 255, 255, 0.95); }
.cloud-mid { background: rgba(232, 240, 254, 0.85); filter: blur(28px); }
.cloud-front { background: rgba(186, 207, 230, 0.70); filter: blur(34px); }
/* Sky variants for the page header (transparent over sky) */
.header-on-sky {
background: transparent !important;
border-color: transparent !important;
backdrop-filter: none !important;
}
.header-on-sky a,
.header-on-sky button,
.header-on-sky span,
.header-on-sky svg { color: white; }
.header-on-sky .nav-link {
color: rgba(255, 255, 255, 0.78);
}
.header-on-sky .nav-link:hover {
color: white;
background: rgba(255, 255, 255, 0.10);
}
.header-on-sky .nav-link.is-active {
color: white;
background: rgba(255, 255, 255, 0.14);
}
.header-on-sky .cta-primary {
background: white;
color: #0c4a6e;
}
.header-on-sky .cta-primary:hover { background: rgba(255, 255, 255, 0.9); }
.header-on-sky .cta-ghost {
color: rgba(255, 255, 255, 0.85);
}
.header-on-sky .cta-ghost:hover {
color: white;
background: rgba(255, 255, 255, 0.10);
}
/* Hairline + soft inner-edge for product mock cards */
.glass-card {
background: color-mix(in oklab, var(--card) 92%, transparent);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
box-shadow:
0 1px 0 0 color-mix(in oklab, white 70%, transparent) inset,
0 30px 80px -40px color-mix(in oklab, oklch(0.20 0.06 250) 30%, transparent),
0 8px 24px -16px color-mix(in oklab, oklch(0.20 0.06 250) 20%, transparent);
}
.dark .glass-card {
box-shadow:
0 1px 0 0 color-mix(in oklab, white 8%, transparent) inset,
0 30px 80px -40px black,
0 8px 24px -16px black;
}
/* Subtle marquee for logo strip */
@keyframes marquee-x {
from { transform: translateX(0); }
to { transform: translateX(-50%); }
}
.marquee-track {
animation: marquee-x 38s linear infinite;
}
/* Mask the edges of a horizontal marquee to fade in/out */
.marquee-mask {
mask-image: linear-gradient(to right, transparent 0%, black 8%, black 92%, transparent 100%);
-webkit-mask-image: linear-gradient(to right, transparent 0%, black 8%, black 92%, transparent 100%);
}
/* Inline code style for the docs/learn pages. */
.kbd {
font-family: var(--font-mono);