From c0f677ccc98ea6d094ac83e0e8d235fde4a10c1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Tue, 7 Jul 2026 22:08:31 -0400 Subject: [PATCH] Rebuild navbar, hero, and feature sections in adaline style MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - navbar: sticky, transparent to blur-on-scroll, wordmark + mono nav links + theme toggle + Download CTA, Reicon Menu/Xmark icons (components/layout) - theme-toggle: Reicon Sun/Moon icons - hero: meadow badge, tight Instrument Sans headline, Download + How-it-works CTAs, availability line, framed dashboard shot (components/sections) - features: five stacked heading-over-panel sections mapping the org chart, office, messages, connectors and cost-control screens - ui/media-frame: shared framed product-shot panel - reveal: progressive enhancement — content is visible without JS and only hidden once the js class is present, then revealed on scroll - remove the superseded flat navbar/hero/features components Verified: next build green; desktop + mobile screenshots reviewed. --- landing/app/globals.css | 17 +- landing/app/layout.tsx | 2 +- landing/app/page.tsx | 6 +- landing/components/features.tsx | 191 ------------------ landing/components/hero.tsx | 129 ------------ landing/components/layout/navbar.tsx | 114 +++++++++++ landing/components/navbar.tsx | 132 ------------ .../components/sections/feature-section.tsx | 18 ++ landing/components/sections/features.tsx | 15 ++ landing/components/sections/hero.tsx | 65 ++++++ landing/components/theme-toggle.tsx | 30 +-- landing/components/ui/media-frame.tsx | 29 +++ 12 files changed, 261 insertions(+), 487 deletions(-) delete mode 100644 landing/components/features.tsx delete mode 100644 landing/components/hero.tsx create mode 100644 landing/components/layout/navbar.tsx delete mode 100644 landing/components/navbar.tsx create mode 100644 landing/components/sections/feature-section.tsx create mode 100644 landing/components/sections/features.tsx create mode 100644 landing/components/sections/hero.tsx create mode 100644 landing/components/ui/media-frame.tsx diff --git a/landing/app/globals.css b/landing/app/globals.css index b8480d5f..97be94da 100644 --- a/landing/app/globals.css +++ b/landing/app/globals.css @@ -179,17 +179,24 @@ body { animation: rise-enter 0.55s cubic-bezier(0.22, 1, 0.36, 1) both; } -/* Scroll-reveal primitive: hidden until IntersectionObserver marks it in view. */ +/* + * Scroll-reveal primitive. Progressive enhancement: content is visible by + * default and only starts hidden once the `js` class is present, so the page + * stays fully readable if scripts never run. + */ .reveal { - opacity: 0; - transform: translateY(16px); transition: opacity 0.6s cubic-bezier(0.22, 1, 0.36, 1), transform 0.6s cubic-bezier(0.22, 1, 0.36, 1); transition-delay: var(--reveal-delay, 0ms); } -.reveal[data-in-view="true"] { +.js .reveal { + opacity: 0; + transform: translateY(16px); +} + +.js .reveal[data-in-view="true"] { opacity: 1; transform: translateY(0); } @@ -208,7 +215,7 @@ body { transition-duration: 0.01ms !important; } - .reveal { + .js .reveal { opacity: 1; transform: none; } diff --git a/landing/app/layout.tsx b/landing/app/layout.tsx index 4982762e..c8cf55de 100644 --- a/landing/app/layout.tsx +++ b/landing/app/layout.tsx @@ -99,7 +99,7 @@ export const metadata: Metadata = { }; const themeScript = ` -(function(){try{var t=localStorage.getItem("agentcompany-theme");if(t==="dark"||(!t&&window.matchMedia("(prefers-color-scheme:dark)").matches)){document.documentElement.classList.add("dark")}}catch(e){}})(); +(function(){document.documentElement.classList.add("js");try{var t=localStorage.getItem("agentcompany-theme");if(t==="dark"||(!t&&window.matchMedia("(prefers-color-scheme:dark)").matches)){document.documentElement.classList.add("dark")}}catch(e){}})(); `; const softwareJsonLd = { diff --git a/landing/app/page.tsx b/landing/app/page.tsx index 769e26dd..dbde0cd3 100644 --- a/landing/app/page.tsx +++ b/landing/app/page.tsx @@ -1,10 +1,10 @@ import { DownloadSection } from "../components/download-section"; import { FAQ } from "../components/faq"; -import { Features } from "../components/features"; +import { Features } from "../components/sections/features"; import { Footer } from "../components/footer"; -import { Hero } from "../components/hero"; +import { Hero } from "../components/sections/hero"; import { HowItWorks } from "../components/how-it-works"; -import { Navbar } from "../components/navbar"; +import { Navbar } from "../components/layout/navbar"; import { RuntimesBar } from "../components/runtimes-bar"; export default function Page() { diff --git a/landing/components/features.tsx b/landing/components/features.tsx deleted file mode 100644 index 26d77088..00000000 --- a/landing/components/features.tsx +++ /dev/null @@ -1,191 +0,0 @@ -"use client"; - -import { motion } from "framer-motion"; - -const features = [ - { - number: "01", - title: "One-Click Company Creation", - description: - "Name your company, describe your mission, connect your AI runtime, and launch. Your first agents start working in under a minute.", - image: "/screenshots/Onboarding.jpeg", - imageAlt: "Company creation onboarding flow with mission and runtime setup", - imageLeft: true, - }, - { - number: "02", - title: "Self-Organizing Teams", - description: - "Your AI CEO builds the org chart. It identifies the roles needed, hires specialists, and creates reporting lines — all from a single goal.", - image: "/screenshots/Auto-OrgChart-Team.jpeg", - imageAlt: "AI-generated org chart showing self-organizing team structure", - imageLeft: false, - }, - { - number: "03", - title: "Autonomous Task Management", - description: - "Goals break down into tasks automatically. Agents pick up work, report progress, and escalate blockers — you decide when to step in.", - image: "/screenshots/Auto-Task.jpeg", - imageAlt: "Autonomous task board with agents managing work items", - imageLeft: true, - }, - { - number: "04", - title: "Real-Time Agent Communication", - description: - "Agents communicate through department channels and direct messages. Watch strategic decisions happen in real time, like a Slack workspace you built.", - image: "/screenshots/AI-Internal-Realtime-Message.jpeg", - imageAlt: "Real-time messaging between AI agents in department channels", - }, - { - number: "05", - title: "Human-in-the-Loop Approvals", - description: - "Stay in control. Critical decisions surface for your review. Approve, reject, or redirect — your company respects the chain of command.", - image: "/screenshots/Approval-by-Human.jpeg", - imageAlt: "Approval interface showing human review of agent decisions", - }, - { - number: "06", - title: "AI Document Generation", - description: - "Business plans, marketing strategies, technical specs — agents draft and iterate on real deliverables, stored in your document center.", - image: "/screenshots/Document-Center.jpeg", - imageAlt: "Document center with AI-generated business deliverables", - }, -]; - -function FeaturePair({ feature }: { feature: (typeof features)[number] }) { - const { number, title, description, image, imageAlt, imageLeft } = feature; - const ease: [number, number, number, number] = [0.16, 1, 0.3, 1]; - - const media = ( - -
- {imageAlt} -
-
- ); - - const copy = ( - - - {number} - -
-
- - {number} -
-

{title}

-

{description}

-
-
- ); - - return ( -
- {media} - {copy} -
- ); -} - -export function Features() { - return ( -
-
- - - Features - -

- Your Company, Under the Hood -

-
- -
- {features.slice(0, 3).map((feature) => ( - - ))} -
- - - {features.slice(3).map((feature) => ( - -
- {feature.imageAlt} -
-
-
- - {feature.number} -
-

{feature.title}

-

{feature.description}

-
-
- ))} -
-
-
- ); -} diff --git a/landing/components/hero.tsx b/landing/components/hero.tsx deleted file mode 100644 index 1cf01bf8..00000000 --- a/landing/components/hero.tsx +++ /dev/null @@ -1,129 +0,0 @@ -"use client"; - -import { motion } from "framer-motion"; -import { AsciiBackground } from "./ascii-background"; -import { landingHeroNarrative } from "../lib/product-narrative"; - -const sharedEase: [number, number, number, number] = [0.16, 1, 0.3, 1]; - -function heroMotion(delay: number) { - return { - initial: { opacity: 0, y: 24 }, - animate: { opacity: 1, y: 0 }, - transition: { duration: 0.7, delay, ease: sharedEase }, - }; -} - -function AppleIcon() { - return ( - - ); -} - -function WindowsIcon() { - return ( - - ); -} - -function LinuxIcon() { - return ( - - ); -} - -export function Hero() { - return ( -
- -
- ); -} diff --git a/landing/components/layout/navbar.tsx b/landing/components/layout/navbar.tsx new file mode 100644 index 00000000..80cd72ae --- /dev/null +++ b/landing/components/layout/navbar.tsx @@ -0,0 +1,114 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { Menu } from "reicon-react/icons/Menu"; +import { Xmark } from "reicon-react/icons/Xmark"; +import { Container } from "../ui/container"; +import { Button } from "../ui/button"; +import { IconMark } from "../icon-mark"; +import { ThemeToggle } from "../theme-toggle"; + +const navLinks = [ + { label: "Features", href: "#features" }, + { label: "How it works", href: "#how-it-works" }, + { label: "FAQ", href: "#faq" }, +]; + +export function Navbar() { + const [mobileOpen, setMobileOpen] = useState(false); + const [scrolled, setScrolled] = useState(false); + + useEffect(() => { + const onScroll = () => setScrolled(window.scrollY > 8); + window.addEventListener("scroll", onScroll, { passive: true }); + onScroll(); + return () => window.removeEventListener("scroll", onScroll); + }, []); + + useEffect(() => { + const onResize = () => { + if (window.innerWidth >= 768) { + setMobileOpen(false); + } + }; + window.addEventListener("resize", onResize, { passive: true }); + return () => window.removeEventListener("resize", onResize); + }, []); + + return ( + + ); +} diff --git a/landing/components/navbar.tsx b/landing/components/navbar.tsx deleted file mode 100644 index 26444012..00000000 --- a/landing/components/navbar.tsx +++ /dev/null @@ -1,132 +0,0 @@ -"use client"; - -import { useEffect, useState } from "react"; -import { IconMark } from "./icon-mark"; -import { ThemeToggle } from "./theme-toggle"; - -const navLinks = [ - { label: "Features", href: "#features" }, - { label: "How It Works", href: "#how-it-works" }, - { label: "FAQ", href: "#faq" }, - { label: "Download", href: "#download" }, -]; - -function MenuIcon({ open }: { open: boolean }) { - return ( - - ); -} - -export function Navbar() { - const [mobileOpen, setMobileOpen] = useState(false); - const [scrolled, setScrolled] = useState(false); - - useEffect(() => { - const handleScroll = () => setScrolled(window.scrollY > 8); - window.addEventListener("scroll", handleScroll, { passive: true }); - handleScroll(); - return () => window.removeEventListener("scroll", handleScroll); - }, []); - - useEffect(() => { - const handleResize = () => { - if (window.innerWidth >= 768) { - setMobileOpen(false); - } - }; - - window.addEventListener("resize", handleResize, { passive: true }); - return () => window.removeEventListener("resize", handleResize); - }, []); - - return ( - - ); -} diff --git a/landing/components/sections/feature-section.tsx b/landing/components/sections/feature-section.tsx new file mode 100644 index 00000000..9c7a3846 --- /dev/null +++ b/landing/components/sections/feature-section.tsx @@ -0,0 +1,18 @@ +import { Reveal } from "../ui/reveal"; +import { SectionHeading } from "../ui/section-heading"; +import { MediaFrame } from "../ui/media-frame"; +import type { FeatureSection as FeatureSectionData } from "../../lib/landing-content"; + +/** One feature: heading + subhead above a full-width product panel (adaline rhythm). */ +export function FeatureSection({ feature }: { feature: FeatureSectionData }) { + return ( +
+ + + + + + +
+ ); +} diff --git a/landing/components/sections/features.tsx b/landing/components/sections/features.tsx new file mode 100644 index 00000000..1b45bb11 --- /dev/null +++ b/landing/components/sections/features.tsx @@ -0,0 +1,15 @@ +import { Container } from "../ui/container"; +import { FeatureSection } from "./feature-section"; +import { featureSections } from "../../lib/landing-content"; + +export function Features() { + return ( +
+ + {featureSections.map((feature) => ( + + ))} + +
+ ); +} diff --git a/landing/components/sections/hero.tsx b/landing/components/sections/hero.tsx new file mode 100644 index 00000000..6adfad94 --- /dev/null +++ b/landing/components/sections/hero.tsx @@ -0,0 +1,65 @@ +import { Container } from "../ui/container"; +import { Badge } from "../ui/badge"; +import { Button } from "../ui/button"; +import { MediaFrame } from "../ui/media-frame"; +import { landingHeroNarrative } from "../../lib/product-narrative"; + +export function Hero() { + return ( +
+
+ ); +} diff --git a/landing/components/theme-toggle.tsx b/landing/components/theme-toggle.tsx index 7434d0b4..a286657f 100644 --- a/landing/components/theme-toggle.tsx +++ b/landing/components/theme-toggle.tsx @@ -1,31 +1,9 @@ "use client"; +import { Sun } from "reicon-react/icons/Sun"; +import { Moon } from "reicon-react/icons/Moon"; import { useTheme } from "./theme-provider"; -function SunIcon() { - return ( - - ); -} - -function MoonIcon() { - return ( - - ); -} - export function ThemeToggle() { const { theme, toggleTheme } = useTheme(); @@ -34,9 +12,9 @@ export function ThemeToggle() { type="button" onClick={toggleTheme} aria-label={`Switch to ${theme === "light" ? "dark" : "light"} mode`} - className="relative inline-flex items-center justify-center w-11 h-11 rounded-lg transition-colors duration-200 cursor-pointer hover:bg-[var(--panel-soft)] text-[var(--muted)] hover:text-[var(--text)]" + className="inline-flex h-9 w-9 cursor-pointer items-center justify-center rounded-full text-[var(--muted)] transition-colors hover:bg-[var(--panel-soft)] hover:text-[var(--text)]" > - {theme === "light" ? : } + {theme === "light" ? : } ); } diff --git a/landing/components/ui/media-frame.tsx b/landing/components/ui/media-frame.tsx new file mode 100644 index 00000000..51543a81 --- /dev/null +++ b/landing/components/ui/media-frame.tsx @@ -0,0 +1,29 @@ +/** Framed product screenshot panel: rounded, bordered, soft shadow on the page. */ +export function MediaFrame({ + src, + alt, + priority = false, + className = "", +}: { + src: string; + alt: string; + priority?: boolean; + className?: string; +}) { + return ( +
+ {alt} +
+ ); +}