chore: format with prettier [skip ci]
This commit is contained in:
parent
8579136b48
commit
48bdfc06b3
|
|
@ -210,43 +210,46 @@ export function LandingFeatures() {
|
|||
[feedbackId],
|
||||
);
|
||||
|
||||
useGSAP(() => {
|
||||
// Desktop: pin the section so the viewport locks onto it, then advance
|
||||
// through the four features (text + mockup crossfade) as you scroll, with a
|
||||
// snap to each one. The pin owns a defined scroll region, so the layout and
|
||||
// every trigger below stays stable. Mobile renders the features stacked.
|
||||
const mm = gsap.matchMedia();
|
||||
useGSAP(
|
||||
() => {
|
||||
// Desktop: pin the section so the viewport locks onto it, then advance
|
||||
// through the four features (text + mockup crossfade) as you scroll, with a
|
||||
// snap to each one. The pin owns a defined scroll region, so the layout and
|
||||
// every trigger below stays stable. Mobile renders the features stacked.
|
||||
const mm = gsap.matchMedia();
|
||||
|
||||
mm.add("(min-width: 1024px)", () => {
|
||||
const st = ScrollTrigger.create({
|
||||
trigger: pinRef.current,
|
||||
pin: true,
|
||||
start: "top top",
|
||||
// Short, snappy travel between features (~0.6 viewport each) instead
|
||||
// of a full screen of scrolling per switch.
|
||||
end: () => "+=" + window.innerHeight * 1.8,
|
||||
anticipatePin: 1,
|
||||
invalidateOnRefresh: true,
|
||||
snap: {
|
||||
snapTo: [0, 1 / 3, 2 / 3, 1],
|
||||
duration: { min: 0.25, max: 0.5 },
|
||||
delay: 0.05,
|
||||
ease: "power2.inOut",
|
||||
},
|
||||
onUpdate: (self) => {
|
||||
const idx = Math.min(3, Math.round(self.progress * 3));
|
||||
if (idx !== activeRef.current) {
|
||||
activeRef.current = idx;
|
||||
setActive(idx);
|
||||
}
|
||||
},
|
||||
mm.add("(min-width: 1024px)", () => {
|
||||
const st = ScrollTrigger.create({
|
||||
trigger: pinRef.current,
|
||||
pin: true,
|
||||
start: "top top",
|
||||
// Short, snappy travel between features (~0.6 viewport each) instead
|
||||
// of a full screen of scrolling per switch.
|
||||
end: () => "+=" + window.innerHeight * 1.8,
|
||||
anticipatePin: 1,
|
||||
invalidateOnRefresh: true,
|
||||
snap: {
|
||||
snapTo: [0, 1 / 3, 2 / 3, 1],
|
||||
duration: { min: 0.25, max: 0.5 },
|
||||
delay: 0.05,
|
||||
ease: "power2.inOut",
|
||||
},
|
||||
onUpdate: (self) => {
|
||||
const idx = Math.min(3, Math.round(self.progress * 3));
|
||||
if (idx !== activeRef.current) {
|
||||
activeRef.current = idx;
|
||||
setActive(idx);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return () => st.kill();
|
||||
});
|
||||
|
||||
return () => st.kill();
|
||||
});
|
||||
|
||||
return () => mm.revert();
|
||||
}, { scope: containerRef });
|
||||
return () => mm.revert();
|
||||
},
|
||||
{ scope: containerRef },
|
||||
);
|
||||
|
||||
// Fluid swap between features: outgoing fades out while the incoming text
|
||||
// rises line-by-line and the mockup settles in with a soft scale. Runs on
|
||||
|
|
@ -337,8 +340,8 @@ export function LandingFeatures() {
|
|||
</div>
|
||||
<div className="lg:col-span-5">
|
||||
<p className="landing-body-compact">
|
||||
Your agents stay native terminal tools. AO standardizes launch, restore, hooks, and PR ownership through one
|
||||
adapter contract.
|
||||
Your agents stay native terminal tools. AO standardizes launch, restore, hooks, and PR ownership through
|
||||
one adapter contract.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -418,9 +421,10 @@ function FeatureNarrative({ worker, orchestrator }: { worker: AgentHarness; orch
|
|||
meta="23 harnesses"
|
||||
>
|
||||
<p>
|
||||
Run <FeatureStrong>{worker.name}</FeatureStrong>, <FeatureStrong>{orchestrator.name}</FeatureStrong>, Cursor,
|
||||
or Aider unchanged. AO standardizes the workflow around them — <FeatureStrong>restore, prompts, hooks, and
|
||||
ownership</FeatureStrong> — so you can pick one agent to write and another to supervise.
|
||||
Run <FeatureStrong>{worker.name}</FeatureStrong>, <FeatureStrong>{orchestrator.name}</FeatureStrong>, Cursor, or
|
||||
Aider unchanged. AO standardizes the workflow around them —{" "}
|
||||
<FeatureStrong>restore, prompts, hooks, and ownership</FeatureStrong> — so you can pick one agent to write and
|
||||
another to supervise.
|
||||
</p>
|
||||
</FeatureCopy>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -555,30 +555,36 @@ function SessionDot({ zone }: { zone: string }) {
|
|||
export function LandingHero() {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useGSAP(() => {
|
||||
const ctx = gsap.context(() => {
|
||||
const tl = gsap.timeline({ defaults: { ease: "power4.out" } });
|
||||
|
||||
// Initial state
|
||||
gsap.set(".gsap-reveal", { y: 40, opacity: 0 });
|
||||
gsap.set(".gsap-scale", { scale: 0.95, opacity: 0 });
|
||||
useGSAP(
|
||||
() => {
|
||||
const ctx = gsap.context(() => {
|
||||
const tl = gsap.timeline({ defaults: { ease: "power4.out" } });
|
||||
|
||||
tl.to(".gsap-reveal", {
|
||||
y: 0,
|
||||
opacity: 1,
|
||||
duration: 1.2,
|
||||
stagger: 0.15,
|
||||
})
|
||||
.to(".gsap-scale", {
|
||||
scale: 1,
|
||||
opacity: 1,
|
||||
duration: 1.2,
|
||||
ease: "elastic.out(1, 0.75)"
|
||||
}, "-=0.8");
|
||||
}, containerRef);
|
||||
// Initial state
|
||||
gsap.set(".gsap-reveal", { y: 40, opacity: 0 });
|
||||
gsap.set(".gsap-scale", { scale: 0.95, opacity: 0 });
|
||||
|
||||
return () => ctx.revert();
|
||||
}, { scope: containerRef });
|
||||
tl.to(".gsap-reveal", {
|
||||
y: 0,
|
||||
opacity: 1,
|
||||
duration: 1.2,
|
||||
stagger: 0.15,
|
||||
}).to(
|
||||
".gsap-scale",
|
||||
{
|
||||
scale: 1,
|
||||
opacity: 1,
|
||||
duration: 1.2,
|
||||
ease: "elastic.out(1, 0.75)",
|
||||
},
|
||||
"-=0.8",
|
||||
);
|
||||
}, containerRef);
|
||||
|
||||
return () => ctx.revert();
|
||||
},
|
||||
{ scope: containerRef },
|
||||
);
|
||||
|
||||
return (
|
||||
<section
|
||||
|
|
@ -629,8 +635,14 @@ export function LandingHero() {
|
|||
<span>Star on GitHub</span>
|
||||
<span className="relative inline-flex items-center">
|
||||
<StarIcon className="gh-star h-4 w-4 text-[color:var(--fg-muted)]" />
|
||||
<span className="gh-sparkle absolute -right-1 -top-1 h-1 w-1 rounded-full bg-[#ffd35c]" style={{ ["--sx" as string]: "7px", ["--sy" as string]: "-7px" }} />
|
||||
<span className="gh-sparkle gh-sparkle-2 absolute -bottom-1 left-0 h-1 w-1 rounded-full bg-[color:var(--accent)]" style={{ ["--sx" as string]: "-6px", ["--sy" as string]: "6px" }} />
|
||||
<span
|
||||
className="gh-sparkle absolute -right-1 -top-1 h-1 w-1 rounded-full bg-[#ffd35c]"
|
||||
style={{ ["--sx" as string]: "7px", ["--sy" as string]: "-7px" }}
|
||||
/>
|
||||
<span
|
||||
className="gh-sparkle gh-sparkle-2 absolute -bottom-1 left-0 h-1 w-1 rounded-full bg-[color:var(--accent)]"
|
||||
style={{ ["--sx" as string]: "-6px", ["--sy" as string]: "6px" }}
|
||||
/>
|
||||
</span>
|
||||
<span className="gh-star-count rounded-full border border-white/10 bg-white/[0.04] px-1.5 py-0.5 text-[12px] leading-none text-[color:var(--fg-muted)]">
|
||||
7.7k
|
||||
|
|
@ -646,7 +658,7 @@ export function LandingHero() {
|
|||
</div>
|
||||
<div className="h-px flex-1 bg-gradient-to-r from-[color:var(--border-strong)] via-[color:var(--border-strong)] to-transparent" />
|
||||
</div>
|
||||
|
||||
|
||||
<div className="gsap-scale mt-12">
|
||||
<ScaledMockup designWidth={1080}>
|
||||
<HeroDashboardMockup />
|
||||
|
|
|
|||
|
|
@ -132,16 +132,16 @@ export function LandingNav() {
|
|||
}, []);
|
||||
|
||||
return (
|
||||
<header data-testid="site-nav" ref={navRef} className="pointer-events-auto fixed inset-x-0 top-0 z-40 pt-4 px-4 transition-all duration-500 ease-out flex justify-center [&.nav-scrolled]:pt-2">
|
||||
<div
|
||||
<header
|
||||
data-testid="site-nav"
|
||||
ref={navRef}
|
||||
className="pointer-events-auto fixed inset-x-0 top-0 z-40 pt-4 px-4 transition-all duration-500 ease-out flex justify-center [&.nav-scrolled]:pt-2"
|
||||
>
|
||||
<div
|
||||
ref={innerRef}
|
||||
className="w-full max-w-6xl mx-auto flex h-14 items-center justify-between gap-6 rounded-full border border-[color:var(--border)] bg-[color:var(--bg)]/70 px-6 backdrop-blur-xl shadow-lg transition-all duration-500 ease-out [.nav-scrolled_&]:h-12 [.nav-scrolled_&]:max-w-4xl [.nav-scrolled_&]:bg-[color:var(--bg)]/90"
|
||||
>
|
||||
<a
|
||||
href="/"
|
||||
data-testid="nav-logo"
|
||||
className="group inline-flex h-10 shrink-0 items-center gap-3"
|
||||
>
|
||||
<a href="/" data-testid="nav-logo" className="group inline-flex h-10 shrink-0 items-center gap-3">
|
||||
<img
|
||||
src="/ao-logo.svg"
|
||||
alt="Agent Orchestrator"
|
||||
|
|
@ -152,10 +152,7 @@ export function LandingNav() {
|
|||
</span>
|
||||
</a>
|
||||
|
||||
<nav
|
||||
className="hidden items-center gap-8 md:flex"
|
||||
aria-label="Primary"
|
||||
>
|
||||
<nav className="hidden items-center gap-8 md:flex" aria-label="Primary">
|
||||
{navLinks.map((item) => (
|
||||
<a
|
||||
key={item.label}
|
||||
|
|
|
|||
|
|
@ -125,33 +125,36 @@ function VerifiedIcon({ className = "" }: { className?: string }) {
|
|||
export function LandingSocialProof() {
|
||||
const containerRef = useRef<HTMLElement>(null);
|
||||
|
||||
useGSAP(() => {
|
||||
const cards = gsap.utils.toArray<HTMLElement>(".gsap-tweet-card");
|
||||
useGSAP(
|
||||
() => {
|
||||
const cards = gsap.utils.toArray<HTMLElement>(".gsap-tweet-card");
|
||||
|
||||
gsap.set(cards, { opacity: 0, y: 30 });
|
||||
gsap.set(cards, { opacity: 0, y: 30 });
|
||||
|
||||
// Reveal each card as it enters the viewport. On mobile the masonry is a
|
||||
// single tall column, so a single section-top trigger left the lower cards
|
||||
// invisible until far past the heading; batching reveals them in step with
|
||||
// the scroll on every layout.
|
||||
const batch = ScrollTrigger.batch(cards, {
|
||||
start: "top 90%",
|
||||
once: true,
|
||||
onEnter: (els: Element[]) => {
|
||||
gsap.to(els, {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
duration: 0.7,
|
||||
stagger: 0.08,
|
||||
ease: "power3.out",
|
||||
});
|
||||
},
|
||||
});
|
||||
// Reveal each card as it enters the viewport. On mobile the masonry is a
|
||||
// single tall column, so a single section-top trigger left the lower cards
|
||||
// invisible until far past the heading; batching reveals them in step with
|
||||
// the scroll on every layout.
|
||||
const batch = ScrollTrigger.batch(cards, {
|
||||
start: "top 90%",
|
||||
once: true,
|
||||
onEnter: (els: Element[]) => {
|
||||
gsap.to(els, {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
duration: 0.7,
|
||||
stagger: 0.08,
|
||||
ease: "power3.out",
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
ScrollTrigger.refresh();
|
||||
ScrollTrigger.refresh();
|
||||
|
||||
return () => batch.forEach((t) => t.kill());
|
||||
}, { scope: containerRef });
|
||||
return () => batch.forEach((t) => t.kill());
|
||||
},
|
||||
{ scope: containerRef },
|
||||
);
|
||||
|
||||
return (
|
||||
<section
|
||||
|
|
@ -249,9 +252,7 @@ function TweetCard({ post, index }: { post: Post; index: number }) {
|
|||
<span className="truncate text-[14px] font-semibold leading-tight text-[color:var(--fg)]">
|
||||
{post.author}
|
||||
</span>
|
||||
{post.verified ? (
|
||||
<VerifiedIcon className="h-3.5 w-3.5 shrink-0 text-[color:var(--accent)]" />
|
||||
) : null}
|
||||
{post.verified ? <VerifiedIcon className="h-3.5 w-3.5 shrink-0 text-[color:var(--accent)]" /> : null}
|
||||
</div>
|
||||
<span className="truncate text-[12px] leading-tight text-[color:var(--fg-dim)]">@{post.handle}</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -130,7 +130,11 @@ body::-webkit-scrollbar,
|
|||
min-height: 100vh;
|
||||
background: var(--bg);
|
||||
color: var(--fg);
|
||||
font-family: var(--font-inter), -apple-system, system-ui, sans-serif;
|
||||
font-family:
|
||||
var(--font-inter),
|
||||
-apple-system,
|
||||
system-ui,
|
||||
sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
|
@ -979,4 +983,3 @@ body::-webkit-scrollbar,
|
|||
transform-box: fill-box;
|
||||
animation: landing-graph-pulse 1.5s ease-out infinite;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue