working demo added
This commit is contained in:
parent
ebbe76d1c4
commit
eb6b5cdb3a
|
|
@ -7,7 +7,6 @@ import { LandingHowItWorks } from "../../components/LandingHowItWorks";
|
|||
import { LandingArchitecture } from "../../components/LandingArchitecture";
|
||||
import { LandingLiveDemo } from "../../components/LandingLiveDemo";
|
||||
import { LandingSocialProof } from "../../components/LandingSocialProof";
|
||||
import { LandingCTA } from "../../components/LandingCTA";
|
||||
import { LandingFooter } from "../../components/LandingFooter";
|
||||
import { ScrollRevealProvider } from "../../components/ScrollRevealProvider";
|
||||
|
||||
|
|
@ -24,7 +23,6 @@ export default function LandingPage() {
|
|||
<LandingArchitecture />
|
||||
<LandingLiveDemo />
|
||||
<LandingSocialProof />
|
||||
<LandingCTA />
|
||||
<LandingFooter />
|
||||
</div>
|
||||
</ScrollRevealProvider>
|
||||
|
|
|
|||
|
|
@ -29,33 +29,53 @@ function DownloadIcon({ className = "" }: { className?: string }) {
|
|||
);
|
||||
}
|
||||
|
||||
const projects = [
|
||||
const appProjects = [
|
||||
{
|
||||
name: "api-gateway",
|
||||
id: "api-gateway",
|
||||
count: 4,
|
||||
tasks: ["Split terminal mux responsibilities", "fix auth timeout retry loop", "add rate limit headers"],
|
||||
sessions: [
|
||||
{ title: "Split terminal mux responsibilities", zone: "working" },
|
||||
{ title: "fix auth timeout retry loop", zone: "error" },
|
||||
{ title: "add rate limit headers", zone: "pending" },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "webgl-preview",
|
||||
id: "webgl-preview",
|
||||
count: 8,
|
||||
tasks: ["Restore fallback renderer affordance", "cache compiled shader programs", "ship frame statistics overlay"],
|
||||
sessions: [
|
||||
{ title: "Restore fallback renderer affordance", zone: "warning" },
|
||||
{ title: "cache compiled shader programs", zone: "error" },
|
||||
{ title: "ship frame statistics overlay", zone: "pending" },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "mobile-shell",
|
||||
id: "mobile-shell",
|
||||
count: 2,
|
||||
tasks: ["repair back swipe gesture", "profile sheet accessibility pass"],
|
||||
sessions: [
|
||||
{ title: "repair back swipe gesture", zone: "working" },
|
||||
{ title: "profile sheet accessibility pass", zone: "success" },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "billing-portal",
|
||||
id: "billing-portal",
|
||||
count: 2,
|
||||
tasks: ["invoice CSV export", "tax id validation errors"],
|
||||
sessions: [
|
||||
{ title: "invoice CSV export", zone: "pending" },
|
||||
{ title: "tax id validation errors", zone: "error" },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const columns = [
|
||||
const appColumns = [
|
||||
{
|
||||
title: "Working",
|
||||
color: "#ffb454",
|
||||
level: "working",
|
||||
color: "#f59f4c",
|
||||
glow: "rgba(245,159,76,0.07)",
|
||||
cards: [
|
||||
{
|
||||
status: "Working",
|
||||
|
|
@ -68,7 +88,9 @@ const columns = [
|
|||
},
|
||||
{
|
||||
title: "Needs you",
|
||||
color: "#ff6b6b",
|
||||
level: "action",
|
||||
color: "#e8c14a",
|
||||
glow: "rgba(232,193,74,0.06)",
|
||||
cards: [
|
||||
{
|
||||
status: "CI failed",
|
||||
|
|
@ -81,7 +103,9 @@ const columns = [
|
|||
},
|
||||
{
|
||||
title: "In review",
|
||||
color: "#8fb7ff",
|
||||
level: "pending",
|
||||
color: "#646a73",
|
||||
glow: "rgba(255,255,255,0.02)",
|
||||
cards: [
|
||||
{
|
||||
status: "Review pending",
|
||||
|
|
@ -94,17 +118,19 @@ const columns = [
|
|||
},
|
||||
{
|
||||
title: "Ready to merge",
|
||||
color: "#72e29b",
|
||||
level: "merge",
|
||||
color: "#74b98a",
|
||||
glow: "rgba(116,185,138,0.07)",
|
||||
cards: [
|
||||
{
|
||||
status: "Mergeable",
|
||||
status: "Ready",
|
||||
agent: "cursor",
|
||||
title: "Build end-to-end onboarding test for published npm package",
|
||||
branch: "test/onboarding-harness",
|
||||
meta: "PR #204 · approved",
|
||||
},
|
||||
{
|
||||
status: "Checks passed",
|
||||
status: "Approved",
|
||||
agent: "aider",
|
||||
title: "publish linux desktop install path",
|
||||
branch: "docs/linux-install",
|
||||
|
|
@ -206,7 +232,6 @@ function SidebarIcon({ className = "" }: { className?: string }) {
|
|||
function HeroDashboardMockup() {
|
||||
const [activeProject, setActiveProject] = useState("api-gateway");
|
||||
const [activeCard, setActiveCard] = useState("fix auth timeout retry loop");
|
||||
const [activeProjectAction, setActiveProjectAction] = useState("api-gateway-board");
|
||||
const [sidebarOpen, setSidebarOpen] = useState(true);
|
||||
const [openProjects, setOpenProjects] = useState<Record<string, boolean>>({
|
||||
"api-gateway": true,
|
||||
|
|
@ -225,150 +250,124 @@ function HeroDashboardMockup() {
|
|||
|
||||
return (
|
||||
<div className="relative mx-auto mt-6 max-w-[1600px]" data-testid="hero-dashboard-interactive">
|
||||
<div className="pointer-events-none absolute -inset-x-8 -inset-y-10 rounded-[30px] bg-[color:var(--accent)] opacity-[0.04] blur-3xl" />
|
||||
<div className="relative overflow-hidden rounded-[18px] border border-[#17191f] bg-[#020203] shadow-[0_34px_120px_-76px_rgba(0,0,0,1)]">
|
||||
<div className="relative overflow-hidden rounded-[18px] border border-[rgba(255,255,255,0.08)] bg-[#0a0b0d] shadow-[0_34px_120px_-76px_rgba(0,0,0,1)]">
|
||||
<div
|
||||
className="grid min-h-[640px] text-left text-[color:var(--fg)] transition-[grid-template-columns] duration-300"
|
||||
style={{ gridTemplateColumns: sidebarOpen ? "264px minmax(0, 1fr)" : "64px minmax(0, 1fr)" }}
|
||||
className="grid min-h-[640px] text-left text-[#f4f5f7] transition-[grid-template-columns] duration-200"
|
||||
style={{
|
||||
gridTemplateColumns: sidebarOpen ? "240px minmax(0, 1fr)" : "52px minmax(0, 1fr)",
|
||||
fontFamily:
|
||||
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Helvetica Neue", sans-serif',
|
||||
}}
|
||||
>
|
||||
<aside className="flex min-h-[640px] flex-col border-b border-[#15171d] bg-[#030304] md:border-b-0 md:border-r">
|
||||
<div className="flex h-14 items-center justify-between border-b border-[#17191f] px-5">
|
||||
<div
|
||||
className={`flex items-center gap-2 text-[15px] font-semibold ${sidebarOpen ? "" : "md:justify-center"}`}
|
||||
<aside className="flex min-h-[640px] overflow-hidden flex-col border-r border-[rgba(255,255,255,0.06)] bg-[#08090b]">
|
||||
<div
|
||||
className={`flex shrink-0 items-center gap-2.5 pt-3.5 ${
|
||||
sidebarOpen ? "px-5 pb-[18px]" : "justify-center px-1.5 pb-2"
|
||||
}`}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
if (sidebarOpen) {
|
||||
setActiveProject("api-gateway");
|
||||
} else {
|
||||
setSidebarOpen(true);
|
||||
}
|
||||
}}
|
||||
className={`grid shrink-0 place-items-center transition-colors ${
|
||||
sidebarOpen ? "h-[22px] w-[22px]" : "h-9 w-9 rounded-lg bg-white/[0.07]"
|
||||
}`}
|
||||
aria-label={sidebarOpen ? "Orchestrator board" : "Expand sidebar"}
|
||||
>
|
||||
<img src="/ao-logo.svg" alt="" className="h-5 w-5" draggable="false" />
|
||||
<span className={sidebarOpen ? "" : "md:hidden"}>Agent Orchestrator</span>
|
||||
</div>
|
||||
<img
|
||||
src="/ao-logo.svg"
|
||||
alt=""
|
||||
className="h-[22px] w-[22px] rounded-[6px] object-cover"
|
||||
draggable="false"
|
||||
/>
|
||||
</button>
|
||||
<span
|
||||
className={`min-w-0 flex-1 truncate text-[14px] font-bold tracking-[-0.015em] ${sidebarOpen ? "" : "hidden"}`}
|
||||
>
|
||||
Agent Orchestrator
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setSidebarOpen((current) => !current)}
|
||||
className="cursor-pointer rounded-md p-1.5 text-[#7a828f] transition-colors hover:bg-white/[0.06] hover:text-white"
|
||||
className={`grid size-[18px] shrink-0 place-items-center rounded-[4px] text-[#646a73] transition-colors hover:bg-white/[0.04] hover:text-[#f4f5f7] ${
|
||||
sidebarOpen ? "" : "hidden"
|
||||
}`}
|
||||
aria-label={sidebarOpen ? "Collapse sidebar" : "Expand sidebar"}
|
||||
aria-expanded={sidebarOpen}
|
||||
>
|
||||
<SidebarIcon className="h-4 w-4" />
|
||||
<SidebarIcon className="h-[15px] w-[15px]" />
|
||||
</button>
|
||||
</div>
|
||||
{sidebarOpen ? (
|
||||
<div className="min-h-0 flex-1 overflow-hidden p-3">
|
||||
<div className="mb-3 flex items-center justify-between px-2 text-[11px] font-bold uppercase tracking-[0.18em] text-[#737b89]">
|
||||
Projects
|
||||
<span className="text-lg font-normal leading-none">+</span>
|
||||
<div className="min-h-0 flex-1 overflow-hidden px-2.5 pr-[7px]">
|
||||
<div className="flex shrink-0 items-center justify-between px-2 pb-2">
|
||||
<div className="text-[10.5px] font-semibold uppercase tracking-[0.09em] text-[#646a73]">Projects</div>
|
||||
<button className="grid h-[18px] w-[18px] place-items-center rounded-[4px] text-[#646a73] transition-colors hover:bg-white/[0.04] hover:text-[#9ba1aa]">
|
||||
<PlusIcon className="h-[13px] w-[13px]" />
|
||||
</button>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
{projects.map((project) => (
|
||||
<div key={project.name} className="group">
|
||||
<div className="space-y-px">
|
||||
{appProjects.map((project) => (
|
||||
<div key={project.id} className="relative">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => toggleProject(project.name)}
|
||||
className={`flex w-full cursor-pointer items-center gap-2 rounded-md px-2 py-2 text-left transition-colors ${
|
||||
activeProject === project.name
|
||||
? "bg-[#11131a] text-[#eceef2]"
|
||||
: "text-[#a0a6b2] hover:bg-[#0b0d12] hover:text-[#eceef2]"
|
||||
aria-expanded={openProjects[project.id]}
|
||||
onClick={() => toggleProject(project.id)}
|
||||
className={`relative flex h-9 w-full items-center gap-[9px] rounded-[5px] px-1.5 py-0 pr-[84px] text-left text-[13px] font-medium transition-colors before:absolute before:bottom-2 before:left-0 before:top-2 before:w-px before:rounded-full ${
|
||||
activeProject === project.id
|
||||
? "bg-white/[0.07] text-[#f4f5f7] before:bg-[#4d8dff]"
|
||||
: "text-[#9ba1aa] before:bg-transparent hover:bg-white/[0.04] hover:text-[#f4f5f7]"
|
||||
}`}
|
||||
>
|
||||
<ChevronIcon
|
||||
className={`h-3.5 w-3.5 shrink-0 transition-transform ${openProjects[project.name] ? "rotate-90" : ""}`}
|
||||
className={`h-[9px] w-[9px] shrink-0 text-[#646a73] transition-transform ${
|
||||
openProjects[project.id] ? "rotate-90" : ""
|
||||
}`}
|
||||
/>
|
||||
<span className="min-w-0 flex-1 truncate text-[15px] font-medium">{project.name}</span>
|
||||
<span className="hidden items-center gap-2 text-[#737b89] group-hover:flex">
|
||||
<span
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label={`${project.name} board`}
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
setActiveProject(project.name);
|
||||
setActiveProjectAction(`${project.name}-board`);
|
||||
}}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === "Enter" || event.key === " ") {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
setActiveProject(project.name);
|
||||
setActiveProjectAction(`${project.name}-board`);
|
||||
}
|
||||
}}
|
||||
className={`cursor-pointer rounded p-0.5 transition-colors hover:bg-white/10 hover:text-white ${
|
||||
activeProjectAction === `${project.name}-board` ? "text-white" : ""
|
||||
}`}
|
||||
>
|
||||
<GridIcon className="h-3.5 w-3.5" />
|
||||
</span>
|
||||
<span
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label={`${project.name} orchestrator`}
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
setActiveProject(project.name);
|
||||
setActiveProjectAction(`${project.name}-orchestrator`);
|
||||
setActiveCard(`Spawn ${project.name} orchestrator`);
|
||||
}}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === "Enter" || event.key === " ") {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
setActiveProject(project.name);
|
||||
setActiveProjectAction(`${project.name}-orchestrator`);
|
||||
setActiveCard(`Spawn ${project.name} orchestrator`);
|
||||
}
|
||||
}}
|
||||
className={`cursor-pointer rounded p-0.5 transition-colors hover:bg-white/10 hover:text-white ${
|
||||
activeProjectAction === `${project.name}-orchestrator` ? "text-white" : ""
|
||||
}`}
|
||||
>
|
||||
<NetworkIcon className="h-3.5 w-3.5" />
|
||||
</span>
|
||||
<span
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label={`${project.name} options`}
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
setActiveProject(project.name);
|
||||
setActiveProjectAction(`${project.name}-options`);
|
||||
}}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === "Enter" || event.key === " ") {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
setActiveProject(project.name);
|
||||
setActiveProjectAction(`${project.name}-options`);
|
||||
}
|
||||
}}
|
||||
className={`cursor-pointer rounded p-0.5 transition-colors hover:bg-white/10 hover:text-white ${
|
||||
activeProjectAction === `${project.name}-options` ? "text-white" : ""
|
||||
}`}
|
||||
>
|
||||
<MoreIcon className="h-3.5 w-3.5" />
|
||||
</span>
|
||||
</span>
|
||||
<span className="min-w-5 rounded-md border border-[#181b22] bg-[#08090c] px-1.5 py-0.5 text-center text-[11px] leading-none text-[#7a828f] group-hover:hidden">
|
||||
<span className="min-w-0 flex-1 truncate">{project.name}</span>
|
||||
<span className="grid h-4 min-w-4 shrink-0 place-items-center rounded bg-white/[0.04] px-1 font-mono text-[10px] leading-none text-[#646a73]">
|
||||
{project.count}
|
||||
</span>
|
||||
</button>
|
||||
{openProjects[project.name] ? (
|
||||
<div className="mt-2 space-y-1.5 pl-8">
|
||||
{project.tasks.map((task, index) => (
|
||||
<div className="absolute right-1 top-0 z-10 flex h-9 items-center gap-px">
|
||||
{[GridIcon, NetworkIcon, MoreIcon].map((Icon, index) => (
|
||||
<button
|
||||
key={`${project.id}-${index}`}
|
||||
type="button"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
setActiveProject(project.id);
|
||||
if (index === 1) setActiveCard(`Spawn ${project.name} orchestrator`);
|
||||
}}
|
||||
className="grid size-5 place-items-center rounded-md text-[#646a73] transition-colors hover:bg-white/[0.04] hover:text-[#f4f5f7] [&_svg]:size-[15px]"
|
||||
aria-label={`${project.name} action ${index + 1}`}
|
||||
>
|
||||
<Icon />
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
{openProjects[project.id] ? (
|
||||
<div className="mx-0 ml-[18px] py-1 pl-2.5">
|
||||
{project.sessions.map((session) => (
|
||||
<button
|
||||
type="button"
|
||||
key={task}
|
||||
className={`flex w-full min-w-0 cursor-pointer items-center gap-2 rounded py-1 text-left text-[13px] transition-colors ${
|
||||
activeCard === task ? "text-[#eceef2]" : "text-[#9aa1ac] hover:text-[#eceef2]"
|
||||
}`}
|
||||
key={session.title}
|
||||
onClick={() => {
|
||||
setActiveProject(project.name);
|
||||
setActiveCard(task);
|
||||
setActiveProject(project.id);
|
||||
setActiveCard(session.title);
|
||||
}}
|
||||
className={`relative flex h-auto w-full items-center gap-[9px] rounded-[4px] py-[5px] pl-2.5 pr-1.5 text-left transition-colors before:absolute before:bottom-1.5 before:left-0 before:top-1.5 before:w-px before:rounded-full ${
|
||||
activeCard === session.title
|
||||
? "text-[#f4f5f7] before:bg-[#4d8dff]"
|
||||
: "text-[#9ba1aa] before:bg-transparent hover:text-[#f4f5f7]"
|
||||
}`}
|
||||
>
|
||||
<span
|
||||
className="h-1.5 w-1.5 shrink-0 rounded-full"
|
||||
style={{
|
||||
backgroundColor: index === 1 ? "#ff7070" : index === 2 ? "#89919e" : "#ffad4d",
|
||||
}}
|
||||
/>
|
||||
<span className="truncate">{task}</span>
|
||||
<SessionDot zone={session.zone} />
|
||||
<span className="min-w-0 flex-1 truncate text-[12px]">{session.title}</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
|
@ -378,104 +377,144 @@ function HeroDashboardMockup() {
|
|||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="hidden min-h-0 flex-1 flex-col items-center gap-3 p-3 md:flex">
|
||||
{projects.map((project) => (
|
||||
<div className="hidden min-h-0 flex-1 flex-col items-center gap-1 px-1.5 md:flex">
|
||||
{appProjects.map((project) => (
|
||||
<button
|
||||
key={project.name}
|
||||
key={project.id}
|
||||
type="button"
|
||||
onClick={() => setActiveProject(project.name)}
|
||||
className={`flex h-9 w-9 cursor-pointer items-center justify-center rounded-lg text-xs font-semibold transition-colors ${
|
||||
activeProject === project.name
|
||||
? "bg-[#11131a] text-[#eceef2]"
|
||||
: "text-[#8a92a0] hover:bg-[#0b0d12] hover:text-white"
|
||||
onClick={() => setActiveProject(project.id)}
|
||||
className={`grid h-9 w-9 place-items-center rounded-lg text-[13px] font-semibold uppercase transition-colors ${
|
||||
activeProject === project.id
|
||||
? "bg-white/[0.07] text-[#f4f5f7]"
|
||||
: "text-[#646a73] hover:bg-white/[0.04] hover:text-[#f4f5f7]"
|
||||
}`}
|
||||
aria-label={project.name}
|
||||
title={project.name}
|
||||
>
|
||||
{project.name.slice(0, 2)}
|
||||
{project.name.charAt(0)}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<button
|
||||
className={`flex h-14 cursor-pointer items-center gap-3 border-t border-[#15171d] px-5 text-sm text-[#8a92a0] transition-colors hover:bg-[#090b10] hover:text-white ${sidebarOpen ? "" : "md:justify-center md:px-0"}`}
|
||||
<div
|
||||
className={`mt-auto border-t border-[rgba(255,255,255,0.06)] p-[7px] ${sidebarOpen ? "" : "flex justify-center"}`}
|
||||
>
|
||||
<SettingsIcon className="h-4 w-4" />
|
||||
<span className={sidebarOpen ? "" : "md:hidden"}>Settings</span>
|
||||
</button>
|
||||
<button
|
||||
className={`flex h-[37px] w-full items-center gap-2.5 rounded-md p-2 text-[13px] font-medium text-[#646a73] transition-colors hover:bg-white/[0.04] hover:text-[#f4f5f7] ${sidebarOpen ? "" : "justify-center"}`}
|
||||
>
|
||||
<SettingsIcon className="h-[15px] w-[15px]" />
|
||||
<span className={sidebarOpen ? "" : "hidden"}>Settings</span>
|
||||
</button>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<div className="min-w-0 bg-[#020203] p-5 sm:p-7">
|
||||
<div className="mb-6 flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
|
||||
<div className="flex items-end gap-3">
|
||||
<h2 className="text-[23px] font-bold leading-none">Board</h2>
|
||||
<p className="pb-0.5 text-[13px] text-[#6f7784]">
|
||||
<div className="flex min-w-0 flex-col bg-[#0a0b0d]">
|
||||
<div className="flex items-center gap-3 px-[18px] pt-[22px]">
|
||||
<div className="flex min-w-0 items-baseline gap-3">
|
||||
<h2 className="text-[21px] font-bold tracking-[-0.025em] text-[#f4f5f7]">Board</h2>
|
||||
<span className="text-[12.5px] text-[#646a73]">
|
||||
Live agent sessions flowing from work → review → merge.
|
||||
</p>
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<div className="ml-auto flex shrink-0 items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setActiveCard("New task drafted")}
|
||||
className="hero-pressable inline-flex cursor-pointer items-center gap-2 rounded-lg border border-[#181b22] bg-[#050608] px-4 py-2 text-sm font-semibold text-[#9aa2af] hover:border-[#2b313d] hover:text-white"
|
||||
className="hero-pressable inline-flex h-[34px] items-center gap-1.5 rounded-[7px] border border-[rgba(255,255,255,0.06)] bg-[#1b1d22] px-[15px] text-[13px] font-semibold leading-none text-[#9ba1aa] hover:bg-[#15171b] hover:text-[#f4f5f7]"
|
||||
>
|
||||
<PlusIcon className="h-4 w-4" />
|
||||
<PlusIcon className="h-3.5 w-3.5" />
|
||||
New task
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setActiveCard("Spawn Orchestrator")}
|
||||
className="hero-pressable inline-flex cursor-pointer items-center gap-2 rounded-lg bg-[color:var(--accent)] px-4 py-2 text-sm font-semibold hover:brightness-110"
|
||||
style={{ color: "#081225" }}
|
||||
className="hero-pressable inline-flex h-[34px] items-center gap-1.5 rounded-[7px] bg-[#4d8dff] px-[15px] text-[13px] font-semibold leading-none text-white hover:brightness-110"
|
||||
>
|
||||
<NetworkIcon className="h-4 w-4" />
|
||||
<NetworkIcon className="h-3.5 w-3.5" />
|
||||
Spawn Orchestrator
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-3 lg:grid-cols-4">
|
||||
{columns.map((column) => (
|
||||
<section key={column.title} className="min-h-[510px] rounded-xl bg-[#07080a] p-4">
|
||||
<div className="mb-5 flex items-center justify-between px-0.5">
|
||||
<div
|
||||
className="flex items-center gap-2 text-[12px] font-bold uppercase tracking-[0.14em]"
|
||||
style={{ color: column.color }}
|
||||
>
|
||||
<span className="h-2 w-2 rounded-full" style={{ backgroundColor: column.color }} />
|
||||
{column.title}
|
||||
</div>
|
||||
<span className="text-xs text-[#68707d]">{column.cards.length}</span>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
{column.cards.map((card) => (
|
||||
<button
|
||||
key={card.title}
|
||||
type="button"
|
||||
onClick={() => setActiveCard(card.title)}
|
||||
className={`hero-pressable w-full cursor-pointer rounded-lg border p-4 text-left ${
|
||||
activeCard === card.title
|
||||
? "border-[#2a3b5d] bg-[#0d111a]"
|
||||
: "border-[#181b22] bg-[#0d0f13] hover:border-[#2b313d] hover:bg-[#11141a]"
|
||||
}`}
|
||||
<div className="min-h-0 flex-1 overflow-hidden p-[18px]">
|
||||
<div className="grid h-full grid-cols-4 gap-2">
|
||||
{appColumns.map((column) => (
|
||||
<section
|
||||
key={column.title}
|
||||
className="flex min-w-0 flex-col overflow-hidden rounded-[13px]"
|
||||
style={{
|
||||
background: `linear-gradient(180deg, ${column.glow}, transparent 130px), rgba(255,255,255,0.018)`,
|
||||
}}
|
||||
>
|
||||
<div className="flex shrink-0 items-center gap-[9px] px-[15px] pb-[11px] pt-[14px]">
|
||||
<span
|
||||
className="h-[7px] w-[7px] rounded-full"
|
||||
style={{
|
||||
background: column.color,
|
||||
boxShadow:
|
||||
column.level === "pending"
|
||||
? undefined
|
||||
: `0 0 7px color-mix(in srgb, ${column.color} 60%, transparent)`,
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className="text-[11px] font-semibold uppercase tracking-[0.08em]"
|
||||
style={{ color: column.color }}
|
||||
>
|
||||
<div className="mb-4 flex items-center justify-between">
|
||||
<span className="flex items-center gap-2 text-xs font-medium" style={{ color: column.color }}>
|
||||
<span className="h-2 w-2 rounded-full" style={{ backgroundColor: column.color }} />
|
||||
{card.status}
|
||||
</span>
|
||||
<span className="font-mono text-[11px] text-[#6e7684]">{card.agent}</span>
|
||||
</div>
|
||||
<div className="text-[14px] font-semibold leading-[1.45] text-[#f0f1f4]">{card.title}</div>
|
||||
<div className="mt-4 font-mono text-[11px] text-[#68707d]">{card.branch}</div>
|
||||
<div className="mt-3 border-t border-[#252933] pt-3 font-mono text-[11px] text-[#68707d]">
|
||||
{card.meta}
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
))}
|
||||
{column.title}
|
||||
</div>
|
||||
<span className="ml-auto font-mono text-[11px] leading-none text-[#646a73]">
|
||||
{column.cards.length}
|
||||
</span>
|
||||
</div>
|
||||
<div className="min-h-0 flex-1 overflow-hidden px-[11px] pb-3">
|
||||
<div className="flex flex-col gap-2.5">
|
||||
{column.cards.map((card) => (
|
||||
<button
|
||||
key={card.title}
|
||||
type="button"
|
||||
onClick={() => setActiveCard(card.title)}
|
||||
className={`w-full rounded-[7px] border bg-[#15171b] text-left transition-colors hover:border-[rgba(255,255,255,0.10)] ${
|
||||
activeCard === card.title
|
||||
? "border-[rgba(77,141,255,0.48)]"
|
||||
: "border-[rgba(255,255,255,0.06)]"
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center gap-2 px-[13px] pb-[9px] pt-3">
|
||||
<span
|
||||
className="inline-flex items-center gap-1.5 text-[11px] font-medium"
|
||||
style={{ color: card.status === "CI failed" ? "#ef6b6b" : column.color }}
|
||||
>
|
||||
<span className="h-[7px] w-[7px] rounded-full bg-current" />
|
||||
{card.status}
|
||||
</span>
|
||||
<span className="ml-auto shrink-0 font-mono text-[10.5px] tracking-[0.04em] text-[#646a73]">
|
||||
{card.agent}
|
||||
</span>
|
||||
</div>
|
||||
<div className="line-clamp-2 overflow-hidden px-[13px] pb-2 text-[13px] font-medium leading-[1.42] tracking-[-0.01em] text-[#f4f5f7]">
|
||||
{card.title}
|
||||
</div>
|
||||
<div className="px-[13px] pb-2.5 font-mono text-[10.5px] text-[#646a73]">{card.branch}</div>
|
||||
<div className="border-t border-[rgba(255,255,255,0.06)] px-[13px] py-2 font-mono text-[10.5px] text-[#646a73]">
|
||||
{card.meta}
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="shrink-0 border-t border-[rgba(255,255,255,0.06)] px-[18px]">
|
||||
<div className="flex min-h-[51px] items-center gap-2 py-2 text-[#9ba1aa]">
|
||||
<ChevronIcon className="h-3 w-3 text-[#646a73]" />
|
||||
<span className="font-mono text-[10.5px] font-medium uppercase tracking-[0.05em]">
|
||||
Done / Terminated
|
||||
</span>
|
||||
<span className="ml-auto shrink-0 font-mono text-[10px] text-[#646a73]">3</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -484,6 +523,20 @@ function HeroDashboardMockup() {
|
|||
);
|
||||
}
|
||||
|
||||
function SessionDot({ zone }: { zone: string }) {
|
||||
const color =
|
||||
zone === "working"
|
||||
? "#f59f4c"
|
||||
: zone === "warning"
|
||||
? "#e8c14a"
|
||||
: zone === "error"
|
||||
? "#ef6b6b"
|
||||
: zone === "success"
|
||||
? "#74b98a"
|
||||
: "#646a73";
|
||||
return <span className="mt-px h-1.5 w-1.5 shrink-0 rounded-full" style={{ background: color }} />;
|
||||
}
|
||||
|
||||
export function LandingHero() {
|
||||
return (
|
||||
<section
|
||||
|
|
@ -505,8 +558,11 @@ export function LandingHero() {
|
|||
<div className="mx-auto max-w-[1500px] text-center">
|
||||
<h1
|
||||
data-testid="hero-headline"
|
||||
className="mx-auto max-w-[1320px] font-display font-semibold leading-[0.98] text-[#f2f3f5]"
|
||||
style={{ fontSize: "clamp(38px, 4.35vw, 78px)", letterSpacing: "-0.035em" }}
|
||||
className="mx-auto max-w-[1280px] font-display font-[650] leading-[1.01] text-[#f2f3f5]"
|
||||
style={{
|
||||
fontSize: "clamp(38px, 4.2vw, 76px)",
|
||||
letterSpacing: "-0.035em",
|
||||
}}
|
||||
>
|
||||
<span className="block">Stop babysitting coding agents.</span>
|
||||
<span className="mt-2 block">
|
||||
|
|
|
|||
|
|
@ -2,14 +2,6 @@
|
|||
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
function GithubIcon({ className = "" }: { className?: string }) {
|
||||
return (
|
||||
<svg className={className} viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
||||
<path d="M12 .5C5.65.5.5 5.65.5 12c0 5.08 3.29 9.38 7.86 10.9.58.1.79-.25.79-.56v-2.15c-3.2.7-3.88-1.37-3.88-1.37-.52-1.34-1.28-1.7-1.28-1.7-1.05-.72.08-.7.08-.7 1.16.08 1.77 1.2 1.77 1.2 1.03 1.76 2.7 1.25 3.36.96.1-.75.4-1.25.73-1.54-2.56-.29-5.26-1.28-5.26-5.7 0-1.26.45-2.29 1.19-3.1-.12-.3-.52-1.47.11-3.05 0 0 .97-.31 3.18 1.18A10.96 10.96 0 0 1 12 5.99c.98 0 1.97.13 2.9.38 2.2-1.49 3.17-1.18 3.17-1.18.63 1.58.23 2.75.11 3.05.74.81 1.19 1.84 1.19 3.1 0 4.43-2.7 5.4-5.27 5.69.41.36.78 1.07.78 2.16v3.2c0 .31.21.67.8.55A11.51 11.51 0 0 0 23.5 12C23.5 5.65 18.35.5 12 .5Z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
function ArrowUpRightIcon({ className = "" }: { className?: string }) {
|
||||
return (
|
||||
<svg className={className} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" aria-hidden="true">
|
||||
|
|
@ -56,11 +48,19 @@ function XSocialIcon({ className = "" }: { className?: string }) {
|
|||
);
|
||||
}
|
||||
|
||||
function DiscordIcon({ className = "" }: { className?: string }) {
|
||||
return (
|
||||
<svg className={className} viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
||||
<path d="M20.32 4.37A19.8 19.8 0 0 0 15.36 2.8a13.7 13.7 0 0 0-.64 1.32 18.4 18.4 0 0 0-5.44 0 13.7 13.7 0 0 0-.64-1.32 19.7 19.7 0 0 0-4.96 1.57C.54 9.04-.32 13.6.1 18.1a19.9 19.9 0 0 0 6.08 3.08c.49-.67.93-1.38 1.3-2.12-.72-.27-1.4-.6-2.05-.98.17-.12.34-.25.5-.38a14.2 14.2 0 0 0 12.14 0c.16.13.33.26.5.38-.65.39-1.34.72-2.06.99.38.74.81 1.45 1.31 2.12a19.9 19.9 0 0 0 6.08-3.08c.5-5.22-.86-9.74-3.58-13.73ZM8.02 15.33c-1.18 0-2.15-1.08-2.15-2.41 0-1.34.95-2.42 2.15-2.42 1.2 0 2.17 1.09 2.15 2.42 0 1.33-.96 2.41-2.15 2.41Zm7.96 0c-1.18 0-2.15-1.08-2.15-2.41 0-1.34.95-2.42 2.15-2.42 1.2 0 2.17 1.09 2.15 2.42 0 1.33-.95 2.41-2.15 2.41Z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
const socials = [
|
||||
{
|
||||
label: "GitHub",
|
||||
href: "https://github.com/AgentWrapper/agent-orchestrator",
|
||||
icon: GithubIcon,
|
||||
label: "Discord",
|
||||
href: "https://discord.com/invite/UZv7JjxbwG",
|
||||
icon: DiscordIcon,
|
||||
},
|
||||
{
|
||||
label: "X",
|
||||
|
|
|
|||
Loading…
Reference in New Issue