571 lines
27 KiB
TypeScript
571 lines
27 KiB
TypeScript
import { Button } from "@/components/ui/button";
|
|
import {
|
|
Activity,
|
|
ArrowRight,
|
|
BadgeCheck,
|
|
Boxes,
|
|
BrainCircuit,
|
|
CloudCog,
|
|
Cpu,
|
|
DatabaseZap,
|
|
FileCheck2,
|
|
Fingerprint,
|
|
GitBranch,
|
|
KeyRound,
|
|
Layers3,
|
|
LockKeyhole,
|
|
Network,
|
|
ShieldCheck,
|
|
Sparkles,
|
|
SquareKanban,
|
|
Target,
|
|
Workflow,
|
|
} from "lucide-react";
|
|
import type { Lang } from "@/app/page";
|
|
|
|
const MANAGER_URL = "https://code.xinghanlab.com/";
|
|
const DOCS_URL = "https://doc.xinghanlab.com/";
|
|
const CONTACT_EMAIL = "november@taijiaicloud.com";
|
|
|
|
const copy = {
|
|
en: {
|
|
eyebrow: "Agnet Swarm",
|
|
heroTitle: "A controlled autonomous AI development team.",
|
|
heroLead:
|
|
"Heicode Swarm turns one product goal into a Swarm Run, then coordinates tasks, shared context, permissions, artifacts, usage and audit across multiple Agnets.",
|
|
primary: "Start from Heicode",
|
|
secondary: "Read docs",
|
|
proof: ["Goal-driven", "Shared resource layer", "Approval and audit", "Azure-ready"],
|
|
cockpitTitle: "Swarm command map",
|
|
cockpitMeta: "One target, many controlled executors",
|
|
cockpitGoal: "Goal",
|
|
cockpitGoalText:
|
|
"Build a SaaS with login, project workspaces, billing, audit and Azure deployment.",
|
|
cockpitNodes: [
|
|
["Product", "Acceptance criteria"],
|
|
["Architect", "Task graph"],
|
|
["Frontend", "User flows"],
|
|
["Backend", "API and data"],
|
|
["Reviewer", "Risk checks"],
|
|
["Ops", "Deployment"],
|
|
],
|
|
layerTitle: "Four layers customers can understand",
|
|
layerDesc:
|
|
"The swarm is not a group chat of bots. It is a productized operating model with clear layers and boundaries.",
|
|
layers: [
|
|
{
|
|
title: "Goal layer",
|
|
desc: "The customer describes the outcome, constraints, resources and delivery target. Heicode keeps the run anchored to the target.",
|
|
},
|
|
{
|
|
title: "Task layer",
|
|
desc: "The platform creates a dynamic task graph. Tasks can split, merge, block, hand off, retry and return to review.",
|
|
},
|
|
{
|
|
title: "Shared resource layer",
|
|
desc: "Task pool, cache, context, artifacts, approvals, model usage and resource permissions become shared infrastructure.",
|
|
},
|
|
{
|
|
title: "Governance layer",
|
|
desc: "Secrets, cloud actions, production deployment, model spending and audit are controlled instead of exposed to every Agnet.",
|
|
},
|
|
],
|
|
flowTitle: "From an idea to an auditable delivery flow",
|
|
flowDesc:
|
|
"Each Swarm Run produces visible progress, reviewable artifacts and a traceable operating record.",
|
|
flowNote:
|
|
"Heicode keeps every run tied to the original target while recording task state, resource usage and approval history.",
|
|
flow: [
|
|
["Input goal", "User describes product intent and constraints."],
|
|
["Create Swarm Run", "Heicode builds the controlled execution instance."],
|
|
["Build task graph", "Tasks are decomposed, scored and assigned."],
|
|
["Execute with Agnets", "Specialized Agnets work with minimal context."],
|
|
["Review artifacts", "Outputs return as specs, code, tests and deployment records."],
|
|
["Approve risk", "Production actions and sensitive access need explicit approval."],
|
|
],
|
|
resourceTitle: "The common resource layer behind the swarm",
|
|
resourceEyebrow: "Shared layer",
|
|
resourceDesc:
|
|
"This is the key difference from ordinary multi-agent demos: Agnets do not freely share secrets or improvise infrastructure. They work through a controlled shared layer.",
|
|
resources: [
|
|
["Task pool", "Stores waiting, running, blocked, review and completed work."],
|
|
["Context cache", "Keeps project facts, decisions, summaries and dependency state."],
|
|
["Score signals", "Pheromone-style signals help prioritize useful paths and avoid repeated dead ends."],
|
|
["Artifact pool", "Stores requirement drafts, code changes, test reports, deployment manifests and review notes."],
|
|
["Approval center", "Routes risky actions back to the client for explicit confirmation."],
|
|
["Secret vault", "Keeps long-lived credentials out of Git, prompts, Markdown and ordinary logs."],
|
|
],
|
|
azureTitle: "Mapped to an Azure-style infrastructure model",
|
|
azureDesc:
|
|
"Heicode explains swarm capability through concepts enterprise customers already recognize: orchestration, identity, storage, secrets, observability and cost control.",
|
|
azure: [
|
|
["Orchestration", "Swarm Run, dynamic task graph, queue and worker scheduling"],
|
|
["Compute", "Agnet execution runtime, sandbox, review worker and deployment worker"],
|
|
["Storage", "Artifacts, task state, context pack, cache and run history"],
|
|
["Identity", "Resource Binding, Resource Grant, least-privilege scope and TTL"],
|
|
["Secrets", "Vault-backed secret_ref with short-lived derived credentials"],
|
|
["Observability", "Event stream, audit log, usage, cost and approval records"],
|
|
],
|
|
featureTitle: "What makes Heicode Swarm different",
|
|
featureEyebrow: "Product features",
|
|
featurePanelEyebrow: "Visible to customer",
|
|
features: [
|
|
{
|
|
title: "Controlled autonomy",
|
|
desc: "Agnets can continue work, but cannot cross permission, budget or production boundaries without approval.",
|
|
},
|
|
{
|
|
title: "Customer-readable progress",
|
|
desc: "Users see what is being built, why a task is blocked, what was produced and what needs approval.",
|
|
},
|
|
{
|
|
title: "Resource-aware execution",
|
|
desc: "Git, docs, SK, model balance, cloud accounts and deployment targets are explicit resources, not hidden prompt text.",
|
|
},
|
|
{
|
|
title: "Delivery-grade artifacts",
|
|
desc: "The run produces specs, task records, code changes, tests, deployment notes and audit history.",
|
|
},
|
|
],
|
|
ctaTitle: "Use a swarm when the task is larger than one prompt",
|
|
ctaDesc:
|
|
"Heicode is designed for software work that needs requirements, roles, code, cloud resources, safety checks and long-running delivery.",
|
|
contact: "Contact",
|
|
},
|
|
zh: {
|
|
eyebrow: "Agnet 蜂群",
|
|
heroTitle: "受控自治的 AI 开发团队。",
|
|
heroLead:
|
|
"Heicode 蜂群把一个产品目标转成一次 Swarm Run,并在多个 Agnet 之间协调任务、共享上下文、权限、成果物、用量和审计。",
|
|
primary: "进入 Heicode",
|
|
secondary: "查看文档",
|
|
proof: ["目标驱动", "共享资源层", "审批与审计", "面向 Azure 部署"],
|
|
cockpitTitle: "蜂群作战地图",
|
|
cockpitMeta: "一个目标,多名受控执行者",
|
|
cockpitGoal: "目标",
|
|
cockpitGoalText:
|
|
"构建一个包含登录、项目空间、计费、审计和 Azure 部署的 SaaS 产品。",
|
|
cockpitNodes: [
|
|
["Product", "验收标准"],
|
|
["Architect", "任务图"],
|
|
["Frontend", "用户流程"],
|
|
["Backend", "API 与数据"],
|
|
["Reviewer", "风险检查"],
|
|
["Ops", "部署上线"],
|
|
],
|
|
layerTitle: "客户能理解的四个层面",
|
|
layerDesc:
|
|
"蜂群不是一组机器人聊天,而是一套产品化运行模型,每一层都有清晰边界。",
|
|
layers: [
|
|
{
|
|
title: "目标层",
|
|
desc: "客户描述交付结果、约束、资源和上线目标,Heicode 让整次执行始终围绕目标推进。",
|
|
},
|
|
{
|
|
title: "任务层",
|
|
desc: "平台生成动态任务图,任务可以拆分、合并、阻塞、交接、重试并回到复核。",
|
|
},
|
|
{
|
|
title: "共享资源层",
|
|
desc: "任务池、缓存、上下文、成果物、审批、模型用量和资源权限成为蜂群共同使用的基础设施。",
|
|
},
|
|
{
|
|
title: "治理层",
|
|
desc: "密钥、云操作、生产部署、模型消耗和审计被统一控制,而不是暴露给每个 Agnet。",
|
|
},
|
|
],
|
|
flowTitle: "从一个想法到可审计的交付流程",
|
|
flowDesc:
|
|
"每一次 Swarm Run 都产生可见进展、可验收成果物和可追踪操作记录。",
|
|
flowNote:
|
|
"Heicode 会让每次运行始终绑定原始目标,同时记录任务状态、资源使用和审批历史。",
|
|
flow: [
|
|
["输入目标", "用户描述产品意图和约束。"],
|
|
["创建 Swarm Run", "Heicode 建立受控执行实例。"],
|
|
["生成任务图", "任务被拆解、评分和分配。"],
|
|
["Agnet 执行", "专业 Agnet 使用最小上下文推进工作。"],
|
|
["成果物复核", "输出需求、代码、测试和部署记录。"],
|
|
["风险审批", "生产动作和敏感访问需要明确确认。"],
|
|
],
|
|
resourceTitle: "蜂群背后的共同资源层",
|
|
resourceEyebrow: "共享资源层",
|
|
resourceDesc:
|
|
"这是区别于普通多 Agent Demo 的关键:Agnet 不自由共享密钥,也不临时乱接基础设施,而是通过受控共享层工作。",
|
|
resources: [
|
|
["任务池", "保存待执行、执行中、阻塞、待复核和已完成的任务。"],
|
|
["上下文缓存", "保存项目事实、决策、摘要和依赖状态。"],
|
|
["评分信号", "类似信息素的信号帮助优先选择有效路径,避免重复踩坑。"],
|
|
["成果物池", "保存需求草案、代码变更、测试报告、部署清单和复核记录。"],
|
|
["审批中心", "把高风险操作回传到客户端,由用户明确确认。"],
|
|
["密钥保管库", "长期凭证不进入 Git、Prompt、Markdown 或普通日志。"],
|
|
],
|
|
azureTitle: "对标 Azure 的基础设施模型",
|
|
azureDesc:
|
|
"Heicode 用企业客户熟悉的概念解释蜂群能力:编排、身份、存储、密钥、观测和成本控制。",
|
|
azure: [
|
|
["编排", "Swarm Run、动态任务图、队列和 Worker 调度"],
|
|
["计算", "Agnet 执行运行时、沙箱、复核 Worker 和部署 Worker"],
|
|
["存储", "成果物、任务状态、Context Pack、缓存和运行历史"],
|
|
["身份", "Resource Binding、Resource Grant、最小权限范围和 TTL"],
|
|
["密钥", "基于 Vault 的 secret_ref 和短期派生凭证"],
|
|
["观测", "事件流、审计日志、用量、成本和审批记录"],
|
|
],
|
|
featureTitle: "Heicode 蜂群的产品特色",
|
|
featureEyebrow: "产品特色",
|
|
featurePanelEyebrow: "客户可见",
|
|
features: [
|
|
{
|
|
title: "受控自治",
|
|
desc: "Agnet 可以持续推进工作,但不能越过权限、预算或生产边界。",
|
|
},
|
|
{
|
|
title: "客户可读的进展",
|
|
desc: "用户可以看到正在做什么、为什么阻塞、产出了什么、哪些动作需要审批。",
|
|
},
|
|
{
|
|
title: "资源感知执行",
|
|
desc: "Git、文档、SK、模型余额、云账号和部署目标都是明确资源,不是隐藏在 Prompt 里的文字。",
|
|
},
|
|
{
|
|
title: "交付级成果物",
|
|
desc: "一次执行会沉淀需求、任务记录、代码变更、测试、部署说明和审计历史。",
|
|
},
|
|
],
|
|
ctaTitle: "当任务大于一次 Prompt,就需要蜂群",
|
|
ctaDesc:
|
|
"Heicode 面向真实软件工作:需求、角色、代码、云资源、安全检查和长周期交付必须被组织起来。",
|
|
contact: "联系咨询",
|
|
},
|
|
} satisfies Record<Lang, {
|
|
eyebrow: string;
|
|
heroTitle: string;
|
|
heroLead: string;
|
|
primary: string;
|
|
secondary: string;
|
|
proof: string[];
|
|
cockpitTitle: string;
|
|
cockpitMeta: string;
|
|
cockpitGoal: string;
|
|
cockpitGoalText: string;
|
|
cockpitNodes: Array<[string, string]>;
|
|
layerTitle: string;
|
|
layerDesc: string;
|
|
layers: Array<{ title: string; desc: string }>;
|
|
flowTitle: string;
|
|
flowDesc: string;
|
|
flowNote: string;
|
|
flow: Array<[string, string]>;
|
|
resourceTitle: string;
|
|
resourceEyebrow: string;
|
|
resourceDesc: string;
|
|
resources: Array<[string, string]>;
|
|
azureTitle: string;
|
|
azureDesc: string;
|
|
azure: Array<[string, string]>;
|
|
featureTitle: string;
|
|
featureEyebrow: string;
|
|
featurePanelEyebrow: string;
|
|
features: Array<{ title: string; desc: string }>;
|
|
ctaTitle: string;
|
|
ctaDesc: string;
|
|
contact: string;
|
|
}>;
|
|
|
|
const layerIcons = [Target, GitBranch, DatabaseZap, ShieldCheck];
|
|
const resourceIcons = [SquareKanban, BrainCircuit, Activity, FileCheck2, BadgeCheck, KeyRound];
|
|
const featureIcons = [LockKeyhole, Fingerprint, Boxes, Layers3];
|
|
|
|
export function SwarmPage({ lang }: { lang: Lang }) {
|
|
const t = copy[lang];
|
|
|
|
return (
|
|
<>
|
|
<section className="relative isolate overflow-hidden bg-[#111820] pt-28 text-white sm:pt-36">
|
|
<div className="absolute inset-0 -z-10 bg-[radial-gradient(circle_at_16%_18%,rgba(245,158,11,0.24),transparent_30%),radial-gradient(circle_at_80%_0%,rgba(20,184,166,0.22),transparent_34%),linear-gradient(135deg,#111820_0%,#182330_45%,#0c1117_100%)]" />
|
|
<div className="absolute inset-0 -z-10 opacity-[0.18] [background-image:linear-gradient(to_right,white_1px,transparent_1px),linear-gradient(to_bottom,white_1px,transparent_1px)] [background-size:44px_44px]" />
|
|
<div className="absolute left-1/2 top-20 -z-10 h-80 w-80 -translate-x-1/2 rounded-full border border-amber-200/20" />
|
|
<div className="mx-auto max-w-7xl px-4 pb-20 sm:px-6 sm:pb-28 lg:px-8">
|
|
<div className="grid gap-12 lg:grid-cols-[0.95fr_1.05fr] lg:items-center">
|
|
<div>
|
|
<div className="inline-flex items-center gap-2 rounded-full border border-white/15 bg-white/8 px-4 py-2 text-sm font-semibold text-amber-100 shadow-2xl backdrop-blur">
|
|
<Sparkles className="h-4 w-4" />
|
|
{t.eyebrow}
|
|
</div>
|
|
<h1 className="mt-7 max-w-4xl text-5xl font-black leading-[0.94] tracking-[-0.06em] sm:text-7xl lg:text-8xl">
|
|
{t.heroTitle}
|
|
</h1>
|
|
<p className="mt-7 max-w-2xl text-lg leading-8 text-white/70 sm:text-xl">
|
|
{t.heroLead}
|
|
</p>
|
|
<div className="mt-9 flex flex-col gap-4 sm:flex-row">
|
|
<Button size="lg" className="h-12 rounded-full bg-amber-300 px-7 text-[#151a20] hover:bg-amber-200" asChild>
|
|
<a href={MANAGER_URL} target="_blank" rel="noreferrer">
|
|
{t.primary}
|
|
<ArrowRight className="h-4 w-4" />
|
|
</a>
|
|
</Button>
|
|
<Button variant="outline" size="lg" className="h-12 rounded-full border-white/25 bg-white/5 px-7 text-white hover:bg-white hover:text-[#151a20]" asChild>
|
|
<a href={DOCS_URL} target="_blank" rel="noreferrer">
|
|
{t.secondary}
|
|
</a>
|
|
</Button>
|
|
</div>
|
|
<div className="mt-8 grid max-w-2xl gap-3 text-sm text-white/70 sm:grid-cols-2">
|
|
{t.proof.map((item) => (
|
|
<div key={item} className="flex items-center gap-2 rounded-full border border-white/10 bg-white/[0.04] px-4 py-2">
|
|
<span className="h-2 w-2 rounded-full bg-teal-300" />
|
|
{item}
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="relative">
|
|
<div className="absolute -inset-6 rounded-[2.5rem] bg-amber-300/10 blur-2xl" />
|
|
<div className="relative overflow-hidden rounded-[2rem] border border-white/15 bg-[#0d1218]/90 p-5 shadow-2xl">
|
|
<div className="flex items-center justify-between border-b border-white/10 pb-4">
|
|
<div>
|
|
<p className="text-xs uppercase tracking-[0.3em] text-white/45">{t.cockpitMeta}</p>
|
|
<h2 className="mt-2 text-xl font-black">{t.cockpitTitle}</h2>
|
|
</div>
|
|
<Network className="h-7 w-7 text-teal-200" />
|
|
</div>
|
|
<div className="mt-5 rounded-3xl border border-amber-200/20 bg-amber-200/10 p-5">
|
|
<p className="text-xs font-bold uppercase tracking-[0.22em] text-amber-100/70">{t.cockpitGoal}</p>
|
|
<p className="mt-2 text-sm leading-6 text-amber-50/80">{t.cockpitGoalText}</p>
|
|
</div>
|
|
<div className="relative mt-5 grid gap-3 sm:grid-cols-2">
|
|
<div className="absolute left-1/2 top-0 hidden h-full w-px bg-gradient-to-b from-transparent via-white/15 to-transparent sm:block" />
|
|
{t.cockpitNodes.map(([role, work], index) => (
|
|
<div key={role} className="group rounded-3xl border border-white/10 bg-white/[0.045] p-4 transition-colors hover:border-teal-200/40">
|
|
<div className="flex items-center justify-between">
|
|
<p className="font-semibold">{role}</p>
|
|
<span className="rounded-full bg-white/10 px-2 py-1 text-[10px] font-bold text-white/55">
|
|
{String(index + 1).padStart(2, "0")}
|
|
</span>
|
|
</div>
|
|
<p className="mt-2 text-xs text-white/50">{work}</p>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section className="py-20 sm:py-28">
|
|
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
|
<SectionIntro title={t.layerTitle} desc={t.layerDesc} eyebrow={t.eyebrow} />
|
|
<div className="mt-14 grid gap-5 md:grid-cols-2 xl:grid-cols-4">
|
|
{t.layers.map((layer, index) => {
|
|
const Icon = layerIcons[index];
|
|
return (
|
|
<article key={layer.title} className="relative overflow-hidden rounded-[1.7rem] border border-border bg-card/70 p-6 shadow-sm">
|
|
<span className="absolute -right-5 -top-5 text-8xl font-black text-secondary/60">
|
|
{String(index + 1).padStart(2, "0")}
|
|
</span>
|
|
<div className="relative flex h-12 w-12 items-center justify-center rounded-2xl bg-foreground text-background">
|
|
<Icon className="h-6 w-6" />
|
|
</div>
|
|
<h3 className="relative mt-6 text-xl font-semibold">{layer.title}</h3>
|
|
<p className="relative mt-3 text-sm leading-7 text-muted-foreground">{layer.desc}</p>
|
|
</article>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section className="border-y border-border bg-card/30 py-20 sm:py-28">
|
|
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
|
<div className="grid gap-12 lg:grid-cols-[0.85fr_1.15fr] lg:items-start">
|
|
<div>
|
|
<p className="text-sm font-bold uppercase tracking-widest text-primary">Swarm Run</p>
|
|
<h2 className="mt-4 text-3xl font-black tracking-tight sm:text-5xl">
|
|
{t.flowTitle}
|
|
</h2>
|
|
<p className="mt-5 text-muted-foreground">{t.flowDesc}</p>
|
|
<div className="mt-8 rounded-[1.7rem] border border-primary/20 bg-primary/10 p-6">
|
|
<div className="flex items-center gap-3">
|
|
<Workflow className="h-5 w-5 text-primary" />
|
|
<p className="font-semibold text-primary">Target - Task - Resource - Audit</p>
|
|
</div>
|
|
<p className="mt-3 text-sm leading-6 text-muted-foreground">
|
|
{t.flowNote}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div className="relative rounded-[2rem] border border-border bg-background/80 p-4 shadow-sm">
|
|
<div className="absolute left-9 top-12 hidden h-[calc(100%-6rem)] w-px bg-border sm:block" />
|
|
<div className="grid gap-3">
|
|
{t.flow.map(([title, desc], index) => (
|
|
<div key={title} className="relative grid gap-3 rounded-[1.4rem] border border-border bg-card/70 p-5 sm:grid-cols-[auto_1fr]">
|
|
<div className="z-10 flex h-11 w-11 items-center justify-center rounded-2xl bg-foreground text-sm font-black text-background">
|
|
{index + 1}
|
|
</div>
|
|
<div>
|
|
<h3 className="font-semibold">{title}</h3>
|
|
<p className="mt-1 text-sm leading-6 text-muted-foreground">{desc}</p>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section className="py-20 sm:py-28">
|
|
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
|
<SectionIntro title={t.resourceTitle} desc={t.resourceDesc} eyebrow={t.resourceEyebrow} />
|
|
<div className="mt-14 grid gap-5 sm:grid-cols-2 lg:grid-cols-3">
|
|
{t.resources.map(([title, desc], index) => {
|
|
const Icon = resourceIcons[index];
|
|
return (
|
|
<article key={title} className="group rounded-[1.7rem] border border-border bg-card/70 p-6 shadow-sm transition-all hover:-translate-y-1 hover:border-primary/40 hover:shadow-xl">
|
|
<div className="mb-5 flex h-12 w-12 items-center justify-center rounded-2xl bg-secondary text-primary transition-colors group-hover:bg-primary group-hover:text-primary-foreground">
|
|
<Icon className="h-6 w-6" />
|
|
</div>
|
|
<h3 className="text-lg font-semibold">{title}</h3>
|
|
<p className="mt-3 text-sm leading-7 text-muted-foreground">{desc}</p>
|
|
</article>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section className="relative overflow-hidden border-y border-border bg-[#111820] py-20 text-white sm:py-28">
|
|
<div className="absolute inset-0 opacity-20 [background-image:linear-gradient(135deg,white_1px,transparent_1px)] [background-size:30px_30px]" />
|
|
<div className="relative mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
|
<div className="grid gap-12 lg:grid-cols-[0.8fr_1.2fr] lg:items-start">
|
|
<div>
|
|
<div className="inline-flex h-12 w-12 items-center justify-center rounded-2xl bg-teal-300 text-[#111820]">
|
|
<CloudCog className="h-6 w-6" />
|
|
</div>
|
|
<h2 className="mt-6 text-3xl font-black tracking-tight sm:text-5xl">{t.azureTitle}</h2>
|
|
<p className="mt-5 text-white/68">{t.azureDesc}</p>
|
|
</div>
|
|
<div className="grid gap-4 sm:grid-cols-2">
|
|
{t.azure.map(([title, desc]) => (
|
|
<article key={title} className="rounded-[1.5rem] border border-white/12 bg-white/[0.055] p-5 backdrop-blur">
|
|
<div className="mb-4 flex items-center gap-3">
|
|
<Cpu className="h-5 w-5 text-amber-200" />
|
|
<h3 className="font-semibold">{title}</h3>
|
|
</div>
|
|
<p className="text-sm leading-6 text-white/58">{desc}</p>
|
|
</article>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section className="py-20 sm:py-28">
|
|
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
|
<div className="grid gap-12 lg:grid-cols-[0.95fr_1.05fr] lg:items-center">
|
|
<div className="rounded-[2rem] border border-border bg-card/60 p-5 shadow-sm">
|
|
<div className="rounded-[1.55rem] border border-border bg-background/80 p-5">
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<p className="text-xs font-bold uppercase tracking-[0.24em] text-primary">{t.featurePanelEyebrow}</p>
|
|
<h3 className="mt-2 text-2xl font-black">{t.featureTitle}</h3>
|
|
</div>
|
|
<Fingerprint className="h-7 w-7 text-primary" />
|
|
</div>
|
|
<div className="mt-6 space-y-3">
|
|
{t.features.map((feature, index) => {
|
|
const Icon = featureIcons[index];
|
|
return (
|
|
<div key={feature.title} className="flex gap-4 rounded-2xl border border-border bg-card/60 p-4">
|
|
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-foreground text-background">
|
|
<Icon className="h-5 w-5" />
|
|
</div>
|
|
<div>
|
|
<h4 className="font-semibold">{feature.title}</h4>
|
|
<p className="mt-1 text-sm leading-6 text-muted-foreground">{feature.desc}</p>
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<p className="text-sm font-bold uppercase tracking-widest text-primary">{t.featureEyebrow}</p>
|
|
<h2 className="mt-4 text-3xl font-black tracking-tight sm:text-5xl">
|
|
{t.featureTitle}
|
|
</h2>
|
|
<p className="mt-5 text-muted-foreground">
|
|
{t.ctaDesc}
|
|
</p>
|
|
<div className="mt-8 grid gap-4 sm:grid-cols-2">
|
|
<Metric value="01" label={lang === "zh" ? "目标驱动执行" : "Goal-driven execution"} />
|
|
<Metric value="02" label={lang === "zh" ? "任务动态回流" : "Dynamic task backflow"} />
|
|
<Metric value="03" label={lang === "zh" ? "资源安全隔离" : "Safe resource isolation"} />
|
|
<Metric value="04" label={lang === "zh" ? "成果可验收" : "Reviewable artifacts"} />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section className="border-t border-border bg-foreground py-20 text-background sm:py-28">
|
|
<div className="mx-auto max-w-7xl px-4 text-center sm:px-6 lg:px-8">
|
|
<h2 className="mx-auto max-w-3xl text-3xl font-black tracking-tight sm:text-5xl">
|
|
{t.ctaTitle}
|
|
</h2>
|
|
<p className="mx-auto mt-5 max-w-2xl text-lg text-background/70">
|
|
{t.ctaDesc}
|
|
</p>
|
|
<div className="mt-10 flex flex-col items-center justify-center gap-4 sm:flex-row">
|
|
<Button size="lg" className="h-12 rounded-full bg-primary px-7 text-primary-foreground hover:bg-primary/90" asChild>
|
|
<a href={MANAGER_URL} target="_blank" rel="noreferrer">
|
|
{t.primary}
|
|
<ArrowRight className="h-4 w-4" />
|
|
</a>
|
|
</Button>
|
|
<Button variant="outline" size="lg" className="h-12 rounded-full border-background/30 bg-transparent px-7 text-background hover:bg-background hover:text-foreground" asChild>
|
|
<a href={`mailto:${CONTACT_EMAIL}`}>
|
|
{t.contact}: {CONTACT_EMAIL}
|
|
</a>
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</>
|
|
);
|
|
}
|
|
|
|
function SectionIntro({
|
|
eyebrow,
|
|
title,
|
|
desc,
|
|
}: {
|
|
eyebrow: string;
|
|
title: string;
|
|
desc: string;
|
|
}) {
|
|
return (
|
|
<div className="mx-auto max-w-2xl text-center">
|
|
<p className="text-sm font-bold uppercase tracking-widest text-primary">
|
|
{eyebrow}
|
|
</p>
|
|
<h2 className="mt-4 text-3xl font-black tracking-tight sm:text-5xl">
|
|
{title}
|
|
</h2>
|
|
<p className="mt-4 leading-7 text-muted-foreground">{desc}</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function Metric({ value, label }: { value: string; label: string }) {
|
|
return (
|
|
<div className="rounded-[1.4rem] border border-border bg-card/70 p-5">
|
|
<p className="text-3xl font-black text-primary">{value}</p>
|
|
<p className="mt-2 text-sm font-semibold text-muted-foreground">{label}</p>
|
|
</div>
|
|
);
|
|
}
|