diff --git a/landing/app/page.tsx b/landing/app/page.tsx index dbde0cd3..47b6d6f1 100644 --- a/landing/app/page.tsx +++ b/landing/app/page.tsx @@ -1,11 +1,11 @@ import { DownloadSection } from "../components/download-section"; -import { FAQ } from "../components/faq"; +import { FAQ } from "../components/sections/faq"; import { Features } from "../components/sections/features"; import { Footer } from "../components/footer"; import { Hero } from "../components/sections/hero"; -import { HowItWorks } from "../components/how-it-works"; +import { HowItWorks } from "../components/sections/how-it-works"; import { Navbar } from "../components/layout/navbar"; -import { RuntimesBar } from "../components/runtimes-bar"; +import { Runtimes } from "../components/sections/runtimes"; export default function Page() { return ( @@ -21,7 +21,7 @@ export default function Page() {
- + diff --git a/landing/components/how-it-works.tsx b/landing/components/how-it-works.tsx deleted file mode 100644 index 79bd784f..00000000 --- a/landing/components/how-it-works.tsx +++ /dev/null @@ -1,149 +0,0 @@ -"use client"; - -import { motion, useInView } from "framer-motion"; -import { useEffect, useRef, useState } from "react"; -import { landingHowItWorksNarrative } from "../lib/product-narrative"; - -const demoMessages = landingHowItWorksNarrative.demoMessages; - -const logTone: Record<(typeof demoMessages)[number]["role"], string> = { - system: "text-[var(--muted-strong)]", -}; - -const dotTone: Record<(typeof demoMessages)[number]["role"], string> = { - system: "bg-[var(--muted-strong)]", -}; - -const steps = landingHowItWorksNarrative.steps; - -function DemoPanel() { - const anchorRef = useRef(null); - const isVisible = useInView(anchorRef, { once: true, amount: 0.4 }); - const [visibleCount, setVisibleCount] = useState(0); - const logRef = useRef(null); - - useEffect(() => { - if (!isVisible) return; - - const timers = demoMessages.map((message, index) => - window.setTimeout(() => setVisibleCount(index + 1), message.delay), - ); - - return () => timers.forEach((timer) => window.clearTimeout(timer)); - }, [isVisible]); - - useEffect(() => { - if (logRef.current) { - logRef.current.scrollTop = logRef.current.scrollHeight; - } - }, [visibleCount]); - - return ( -
-
-
-
- -
- {demoMessages.slice(0, visibleCount).map((message, index) => ( - - - - {message.text} - - ))} - - {visibleCount < demoMessages.length && isVisible && ( -
-
- ); -} - -export function HowItWorks() { - return ( -
-
-
-

- How It Works -

-

- {landingHowItWorksNarrative.heading} -

-
- -
-
- - - - - -
-
-
- ); -} diff --git a/landing/components/runtimes-bar.tsx b/landing/components/runtimes-bar.tsx deleted file mode 100644 index 3f967084..00000000 --- a/landing/components/runtimes-bar.tsx +++ /dev/null @@ -1,117 +0,0 @@ -"use client"; - -import { motion } from "framer-motion"; - -function AnthropicIcon() { - return ( - - ); -} - -function OpenAIIcon() { - return ( - - ); -} - -function GoogleIcon() { - return ( - - ); -} - -function MoonshotIcon() { - return ( - - ); -} - -function ZhipuIcon() { - return ( - - ); -} - -function MiniMaxIcon() { - return ( - - ); -} - -function OllamaIcon() { - return ( - - ); -} - -function ApiIcon() { - return ( - - ); -} - -const runtimes = [ - { name: "Claude Code", provider: "Anthropic", icon: AnthropicIcon }, - { name: "Codex CLI", provider: "OpenAI", icon: OpenAIIcon }, - { name: "Gemini CLI", provider: "Google", icon: GoogleIcon }, - { name: "Kimi", provider: "Moonshot AI", icon: MoonshotIcon }, - { name: "GLM", provider: "Zhipu AI", icon: ZhipuIcon }, - { name: "MiniMax", provider: "MiniMax", icon: MiniMaxIcon }, - { name: "Ollama", provider: "Local", icon: OllamaIcon }, - { name: "Anthropic Compatible API", provider: "Any Provider", icon: ApiIcon }, -]; - -export function RuntimesBar() { - return ( -
-
- -

- Supported AI Runtimes -

-
- {runtimes.map((runtime) => { - const Icon = runtime.icon; - return ( -
- - - - - {runtime.name} - - - {runtime.provider} - -
- ); - })} -
-
-
-
- ); -} diff --git a/landing/components/faq.tsx b/landing/components/sections/faq.tsx similarity index 56% rename from landing/components/faq.tsx rename to landing/components/sections/faq.tsx index e7093b96..f2908206 100644 --- a/landing/components/faq.tsx +++ b/landing/components/sections/faq.tsx @@ -1,8 +1,11 @@ "use client"; -import { motion } from "framer-motion"; import { useState } from "react"; -import { platformSupportSummary } from "../lib/platform-support"; +import { Plus } from "reicon-react/icons/Plus"; +import { Container } from "../ui/container"; +import { Reveal } from "../ui/reveal"; +import { SectionHeading } from "../ui/section-heading"; +import { platformSupportSummary } from "../../lib/platform-support"; const faqs = [ { @@ -45,65 +48,49 @@ const faqs = [ }, ]; -function FaqItem({ question, answer, index }: { question: string; answer: string; index: number }) { +function FaqItem({ question, answer }: { question: string; answer: string }) { const [open, setOpen] = useState(false); return ( - +
- -
-

{answer}

+
+
+

{answer}

+
- +
); } export function FAQ() { return ( -
-
- -

FAQ

-

- Frequently Asked Questions -

-
- -
- {faqs.map((item, index) => ( - +
+ + + + + + {faqs.map((faq) => ( + ))} -
-
+ +
); } diff --git a/landing/components/sections/how-it-works.tsx b/landing/components/sections/how-it-works.tsx new file mode 100644 index 00000000..da2caec3 --- /dev/null +++ b/landing/components/sections/how-it-works.tsx @@ -0,0 +1,42 @@ +import { Container } from "../ui/container"; +import { Reveal } from "../ui/reveal"; +import { SectionHeading } from "../ui/section-heading"; +import { landingHowItWorksNarrative } from "../../lib/product-narrative"; + +const steps = landingHowItWorksNarrative.steps; + +export function HowItWorks() { + return ( +
+ + + + + + +
+ + + +
+ ); +} diff --git a/landing/components/sections/runtimes.tsx b/landing/components/sections/runtimes.tsx new file mode 100644 index 00000000..87bbc941 --- /dev/null +++ b/landing/components/sections/runtimes.tsx @@ -0,0 +1,33 @@ +import { Container } from "../ui/container"; +import { Reveal } from "../ui/reveal"; + +const runtimes = [ + { name: "Claude Code", provider: "Anthropic" }, + { name: "Codex CLI", provider: "OpenAI" }, + { name: "Gemini CLI", provider: "Google" }, + { name: "Kimi", provider: "Moonshot AI" }, + { name: "GLM", provider: "Zhipu AI" }, + { name: "MiniMax", provider: "MiniMax" }, + { name: "Ollama", provider: "Local" }, + { name: "Anthropic-compatible API", provider: "Any provider" }, +]; + +export function Runtimes() { + return ( +
+ + +

Supported runtimes

+
    + {runtimes.map((runtime) => ( +
  • + {runtime.name} + {runtime.provider} +
  • + ))} +
+
+
+
+ ); +}