feat(landing): add landing page components
This commit is contained in:
parent
8b8c9e5e33
commit
1ef37786b1
8
src/components/landing/ambient-light.tsx
Normal file
8
src/components/landing/ambient-light.tsx
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export default function AmbientLight() {
|
||||||
|
return (
|
||||||
|
<div className="pointer-events-none fixed inset-0 -z-10 overflow-hidden">
|
||||||
|
<div className="absolute -top-[30vh] -left-[10vw] h-[70vh] w-[70vw] rounded-full bg-primary/[0.025] blur-[140px]" />
|
||||||
|
<div className="absolute right-0 top-[10vh] h-[50vh] w-[50vw] rounded-full bg-primary/[0.015] blur-[120px]" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
18
src/components/landing/badge.tsx
Normal file
18
src/components/landing/badge.tsx
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import type { ReactNode } from "react";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
icon?: ReactNode;
|
||||||
|
children: ReactNode;
|
||||||
|
className?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function Badge({ icon, children, className = "" }: Props) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={`inline-flex items-center gap-2 rounded-full border border-border/60 bg-muted/50 px-3 py-1 text-xs font-medium text-muted-foreground ${className}`}
|
||||||
|
>
|
||||||
|
{icon}
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
127
src/components/landing/dashboard-mockup.tsx
Normal file
127
src/components/landing/dashboard-mockup.tsx
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
import type { ReactNode } from "react";
|
||||||
|
import { Bot, Code2, GitBranch, GitCommitHorizontal, MessageSquare, Search } from "lucide-react";
|
||||||
|
|
||||||
|
export default function DashboardMockup() {
|
||||||
|
return (
|
||||||
|
<div className="relative mx-auto mt-16 max-w-5xl overflow-hidden rounded-2xl border border-border/40 bg-card/70 shadow-2xl shadow-primary/10 backdrop-blur-md">
|
||||||
|
<div className="flex h-[460px] sm:h-[520px]">
|
||||||
|
{/* Workspace rail */}
|
||||||
|
<div className="hidden w-[64px] shrink-0 flex-col items-center border-r border-border/40 bg-background/80 py-4 sm:flex">
|
||||||
|
<div className="grid size-9 place-items-center rounded-xl bg-primary text-primary-foreground shadow-sm shadow-primary/20">
|
||||||
|
<Code2 className="size-4" />
|
||||||
|
</div>
|
||||||
|
<div className="my-4 h-px w-7 bg-border" />
|
||||||
|
{['GD', 'AI', 'RS'].map((item, index) => (
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
index === 0
|
||||||
|
? "mb-2 grid size-9 place-items-center rounded-lg bg-primary text-[11px] font-bold text-primary-foreground ring-2 ring-primary/20"
|
||||||
|
: "mb-2 grid size-9 place-items-center rounded-xl border border-border bg-card text-[11px] font-bold text-muted-foreground"
|
||||||
|
}
|
||||||
|
key={item}
|
||||||
|
>
|
||||||
|
{item}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Workspace sidebar */}
|
||||||
|
<div className="hidden w-56 shrink-0 flex-col border-r border-border/40 bg-sidebar p-3 md:flex">
|
||||||
|
<div className="mb-4 flex h-9 items-center gap-2 rounded-xl px-2 text-sm font-semibold">
|
||||||
|
<div className="grid size-7 place-items-center rounded-lg bg-primary/10 text-primary">
|
||||||
|
<Code2 className="size-3.5" />
|
||||||
|
</div>
|
||||||
|
GitDataAI
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-cols-2 gap-1 rounded-xl bg-muted/70 p-1 text-xs font-semibold">
|
||||||
|
<div className="rounded-lg bg-card px-2 py-2 text-center shadow-sm ring-1 ring-border">Workplan</div>
|
||||||
|
<div className="px-2 py-2 text-center text-muted-foreground">Channel</div>
|
||||||
|
</div>
|
||||||
|
<div className="mt-5 space-y-1">
|
||||||
|
<SidebarItem active icon={<GitBranch className="size-3.5" />} label="Repositories" />
|
||||||
|
<SidebarItem icon={<GitCommitHorizontal className="size-3.5" />} label="Pull requests" />
|
||||||
|
<SidebarItem icon={<MessageSquare className="size-3.5" />} label="Workplan chat" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Main content */}
|
||||||
|
<div className="flex min-w-0 flex-1 flex-col bg-background/80">
|
||||||
|
<div className="flex h-11 shrink-0 items-center gap-2 border-b border-border/40 px-4 text-[13px]">
|
||||||
|
<span className="text-muted-foreground/50">GitDataAI</span>
|
||||||
|
<span className="text-muted-foreground/20">/</span>
|
||||||
|
<span className="font-semibold">core</span>
|
||||||
|
<div className="ml-auto grid size-9 place-items-center rounded-xl text-muted-foreground/50">
|
||||||
|
<Search className="size-4" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="min-h-0 flex-1 p-4 sm:p-6">
|
||||||
|
<div className="rounded-xl border border-border bg-card shadow-sm">
|
||||||
|
<div className="flex items-center gap-3 border-b border-border px-4 py-3">
|
||||||
|
<div className="grid size-8 place-items-center rounded-lg bg-primary/10 text-primary">
|
||||||
|
<GitCommitHorizontal className="size-4" />
|
||||||
|
</div>
|
||||||
|
<div className="min-w-0 flex-1">
|
||||||
|
<div className="truncate text-[13px] font-semibold">feat: implement AI auto-review</div>
|
||||||
|
<div className="text-[11px] text-muted-foreground">Alice committed 2 hours ago</div>
|
||||||
|
</div>
|
||||||
|
<span className="rounded-lg border border-border bg-muted/40 px-2 py-1 font-mono text-[11px] text-muted-foreground">
|
||||||
|
a1b2c3d
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2 p-4">
|
||||||
|
{[
|
||||||
|
{ name: "src/agent/review.rs", status: "+84", tone: "text-emerald-500" },
|
||||||
|
{ name: "src/api/handler.rs", status: "+27", tone: "text-emerald-500" },
|
||||||
|
{ name: "tests/ai_test.rs", status: "+16", tone: "text-primary" },
|
||||||
|
].map((file) => (
|
||||||
|
<div className="flex items-center gap-3 rounded-xl border border-border/60 bg-muted/20 px-3 py-2 text-[12px]" key={file.name}>
|
||||||
|
<span className="h-2 w-2 rounded-full bg-current text-primary/60" />
|
||||||
|
<span className="min-w-0 flex-1 truncate font-mono text-foreground/80">{file.name}</span>
|
||||||
|
<span className={`font-mono tabular-nums ${file.tone}`}>{file.status}</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="absolute bottom-8 right-8 hidden w-72 rounded-2xl border border-primary/20 bg-card p-4 shadow-xl shadow-primary/10 sm:block">
|
||||||
|
<div className="mb-2 flex items-center gap-2">
|
||||||
|
<div className="grid size-7 place-items-center rounded-lg bg-primary/10 text-primary">
|
||||||
|
<Bot className="size-4" />
|
||||||
|
</div>
|
||||||
|
<span className="text-[12px] font-bold text-primary">AI Reviewer</span>
|
||||||
|
</div>
|
||||||
|
<p className="text-[12px] leading-relaxed text-muted-foreground/80">
|
||||||
|
Review complete. Add a timeout to the API call before merging.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function SidebarItem({
|
||||||
|
active = false,
|
||||||
|
icon,
|
||||||
|
label,
|
||||||
|
}: {
|
||||||
|
active?: boolean;
|
||||||
|
icon: ReactNode;
|
||||||
|
label: string;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
active
|
||||||
|
? "flex h-9 items-center gap-2 rounded-lg bg-primary/10 px-2.5 text-[13px] font-semibold text-primary ring-1 ring-primary/10"
|
||||||
|
: "flex h-9 items-center gap-2 rounded-lg px-2.5 text-[13px] text-muted-foreground"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{icon}
|
||||||
|
<span className="truncate">{label}</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
80
src/components/landing/footer.tsx
Normal file
80
src/components/landing/footer.tsx
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
import { Link } from "react-router";
|
||||||
|
import { Code2 } from "lucide-react";
|
||||||
|
|
||||||
|
export default function Footer() {
|
||||||
|
return (
|
||||||
|
<footer className="border-t border-border/20 bg-muted/[0.1] py-16">
|
||||||
|
<div className="mx-auto max-w-6xl px-6">
|
||||||
|
<div className="grid gap-10 sm:grid-cols-4">
|
||||||
|
{/* Brand */}
|
||||||
|
<div className="sm:col-span-2">
|
||||||
|
<div className="flex items-center gap-2.5 font-bold">
|
||||||
|
<div className="grid size-8 place-items-center rounded-[10px] bg-primary text-primary-foreground shadow-sm shadow-primary/20">
|
||||||
|
<Code2 className="size-4" />
|
||||||
|
</div>
|
||||||
|
<span className="font-heading text-[15px] tracking-tight">
|
||||||
|
GitDataAI
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<p className="mt-4 max-w-xs text-[13px] leading-relaxed text-muted-foreground/60">
|
||||||
|
The all-in-one developer platform — git hosting, real-time
|
||||||
|
collaboration, and AI agents.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Product */}
|
||||||
|
<div>
|
||||||
|
<h4 className="mb-4 text-xs font-semibold uppercase tracking-wider text-muted-foreground/60">
|
||||||
|
Product
|
||||||
|
</h4>
|
||||||
|
<ul className="space-y-3">
|
||||||
|
{[
|
||||||
|
{ label: "Features", href: "#features" },
|
||||||
|
{ label: "Workflow", href: "#workflow" },
|
||||||
|
].map((l) => (
|
||||||
|
<li key={l.label}>
|
||||||
|
<a
|
||||||
|
className="text-[13px] text-muted-foreground/60 transition-colors hover:text-foreground/80"
|
||||||
|
href={l.href}
|
||||||
|
>
|
||||||
|
{l.label}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Account */}
|
||||||
|
<div>
|
||||||
|
<h4 className="mb-4 text-xs font-semibold uppercase tracking-wider text-muted-foreground/60">
|
||||||
|
Account
|
||||||
|
</h4>
|
||||||
|
<ul className="space-y-3">
|
||||||
|
<li>
|
||||||
|
<Link
|
||||||
|
className="text-[13px] text-muted-foreground/60 transition-colors hover:text-foreground/80"
|
||||||
|
to="/auth/login"
|
||||||
|
>
|
||||||
|
Sign in
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Link
|
||||||
|
className="text-[13px] text-muted-foreground/60 transition-colors hover:text-foreground/80"
|
||||||
|
to="/auth/register"
|
||||||
|
>
|
||||||
|
Register
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Bottom bar */}
|
||||||
|
<div className="mt-12 border-t border-border/20 pt-6 text-center text-xs text-muted-foreground/40">
|
||||||
|
© {new Date().getFullYear()} GitDataAI. All rights reserved.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
);
|
||||||
|
}
|
||||||
50
src/components/landing/header.tsx
Normal file
50
src/components/landing/header.tsx
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import { Link } from "react-router";
|
||||||
|
import { Code2, ArrowRight } from "lucide-react";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
|
||||||
|
const navItems = [
|
||||||
|
{ label: "Features", to: "/features" },
|
||||||
|
{ label: "Workflow", to: "/workflow" },
|
||||||
|
{ label: "Pricing", to: "/pricing" },
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function Header() {
|
||||||
|
return (
|
||||||
|
<header className="sticky top-0 z-50 border-b border-border/30 bg-background/80 backdrop-blur-2xl supports-[backdrop-filter]:bg-background/60">
|
||||||
|
<div className="mx-auto flex h-14 max-w-6xl items-center px-6">
|
||||||
|
<Link className="flex items-center gap-2.5 font-bold" to="/">
|
||||||
|
<div className="grid size-8 place-items-center rounded-[10px] bg-primary text-primary-foreground shadow-sm shadow-primary/20">
|
||||||
|
<Code2 className="size-4" />
|
||||||
|
</div>
|
||||||
|
<span className="font-heading text-[15px] tracking-tight">
|
||||||
|
GitDataAI
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<nav className="ml-8 hidden items-center gap-1 sm:flex">
|
||||||
|
{navItems.map((item) => (
|
||||||
|
<Link
|
||||||
|
className="inline-flex h-9 items-center rounded-lg px-3 text-[13px] font-medium text-muted-foreground/70 transition-colors hover:bg-muted hover:text-foreground"
|
||||||
|
key={item.to}
|
||||||
|
to={item.to}
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div className="ml-auto flex items-center gap-3">
|
||||||
|
<Button size="sm" variant="ghost" asChild>
|
||||||
|
<Link to="/auth/login">Sign in</Link>
|
||||||
|
</Button>
|
||||||
|
<Button size="sm" className="shadow-sm shadow-primary/20" asChild>
|
||||||
|
<Link to="/auth/register">
|
||||||
|
Get Started
|
||||||
|
<ArrowRight className="size-3.5" />
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
);
|
||||||
|
}
|
||||||
15
src/components/landing/section.tsx
Normal file
15
src/components/landing/section.tsx
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
export default function Section({
|
||||||
|
children,
|
||||||
|
className = "",
|
||||||
|
id,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
className?: string;
|
||||||
|
id?: string;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<section className={`relative ${className}`} id={id}>
|
||||||
|
<div className="mx-auto max-w-6xl px-6">{children}</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
44
src/components/landing/terminal-demo.tsx
Normal file
44
src/components/landing/terminal-demo.tsx
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import { Layers } from "lucide-react";
|
||||||
|
|
||||||
|
export default function TerminalDemo() {
|
||||||
|
return (
|
||||||
|
<div className="overflow-hidden rounded-2xl border border-border/20 bg-card/60 shadow-2xl backdrop-blur">
|
||||||
|
{/* title bar */}
|
||||||
|
<div className="flex items-center gap-2 border-b border-border/20 px-4 py-3">
|
||||||
|
<div className="size-2.5 rounded-full bg-red-500/40" />
|
||||||
|
<div className="size-2.5 rounded-full bg-amber-500/40" />
|
||||||
|
<div className="size-2.5 rounded-full bg-emerald-500/40" />
|
||||||
|
<span className="ml-3 font-mono text-[11px] text-muted-foreground/40">
|
||||||
|
Terminal
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{/* body */}
|
||||||
|
<div className="p-5 font-mono text-[13px] leading-relaxed">
|
||||||
|
<p className="text-muted-foreground/70">
|
||||||
|
<span className="text-emerald-500">$</span> git clone{" "}
|
||||||
|
<span className="text-sky-400">
|
||||||
|
https://gitdata.ai/acme/backend
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<p className="mt-2 text-muted-foreground/70">
|
||||||
|
<span className="text-emerald-500">$</span> git checkout -b{" "}
|
||||||
|
<span className="text-amber-400">feature/payments</span>
|
||||||
|
</p>
|
||||||
|
<p className="mt-2 text-muted-foreground/70">
|
||||||
|
<span className="text-emerald-500">$</span> git commit -m{" "}
|
||||||
|
<span className="text-primary/70">
|
||||||
|
"feat: add Stripe integration"
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<p className="mt-2 text-foreground/80">
|
||||||
|
<span className="text-emerald-500">$</span> git push origin
|
||||||
|
feature/payments
|
||||||
|
</p>
|
||||||
|
<div className="mt-5 border-t border-border/20 pt-4 text-xs text-muted-foreground/50">
|
||||||
|
<Layers className="mr-1 inline size-3" />
|
||||||
|
PR #128 created · AI review started · #backend notified
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
55
src/page/landing/features-grid.tsx
Normal file
55
src/page/landing/features-grid.tsx
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import { GitMerge, MessageSquare, Bot, Workflow, Shield, Terminal } from "lucide-react";
|
||||||
|
|
||||||
|
const items = [
|
||||||
|
{
|
||||||
|
icon: <GitMerge className="size-5" />,
|
||||||
|
title: "Git Repositories",
|
||||||
|
desc: "Full git hosting with branches, tags, pull requests, code review, and webhooks. HTTPS / SSH clone.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: <MessageSquare className="size-5" />,
|
||||||
|
title: "Real-time Channels",
|
||||||
|
desc: "Threads, reactions, file sharing, and article publishing. Voice channels for your team.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: <Bot className="size-5" />,
|
||||||
|
title: "AI Agents",
|
||||||
|
desc: "Built-in AI for code review, issue triage, and task automation. Persistent memory & streaming.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: <Workflow className="size-5" />,
|
||||||
|
title: "Issue Tracking",
|
||||||
|
desc: "Create, assign, and track issues. Labels, milestones, board view, and pull request linking.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: <Shield className="size-5" />,
|
||||||
|
title: "Enterprise Security",
|
||||||
|
desc: "TOTP 2FA, role-based access, audit logs, SSH keys, and private repositories.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: <Terminal className="size-5" />,
|
||||||
|
title: "Developer Experience",
|
||||||
|
desc: "REST + WebSocket APIs, OpenAPI spec, webhooks, and git-native CLI. By devs, for devs.",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function FeaturesGrid() {
|
||||||
|
return (
|
||||||
|
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
||||||
|
{items.map((f) => (
|
||||||
|
<div
|
||||||
|
className="group relative cursor-pointer overflow-hidden rounded-2xl border border-border/20 bg-card/50 p-6 backdrop-blur transition-[transform,background-color,border-color,box-shadow] duration-300 hover:-translate-y-0.5 hover:border-primary/10 hover:bg-card hover:shadow-xl"
|
||||||
|
key={f.title}
|
||||||
|
>
|
||||||
|
<div className="mb-5 grid size-11 place-items-center rounded-xl bg-primary/[0.05] text-primary ring-1 ring-primary/[0.04] transition-colors group-hover:bg-primary/[0.08]">
|
||||||
|
{f.icon}
|
||||||
|
</div>
|
||||||
|
<h3 className="font-heading text-[15px] font-semibold">{f.title}</h3>
|
||||||
|
<p className="mt-2 text-[13px] leading-relaxed text-muted-foreground/65">
|
||||||
|
{f.desc}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
151
src/page/landing/features.tsx
Normal file
151
src/page/landing/features.tsx
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
import { Link } from "react-router";
|
||||||
|
import { ArrowRight, Zap, GitCommitHorizontal, MessageSquare, Bot } from "lucide-react";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import FeaturesGrid from "./features-grid";
|
||||||
|
|
||||||
|
export default function FeaturesPage() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<section className="py-24 lg:py-32">
|
||||||
|
<div className="mx-auto max-w-6xl px-6">
|
||||||
|
<div className="mx-auto mb-16 max-w-2xl text-center">
|
||||||
|
<div className="inline-flex items-center gap-2 rounded-full border border-border/60 bg-muted/50 px-3 py-1 text-xs font-medium text-muted-foreground">
|
||||||
|
<Zap className="size-3 text-primary" />
|
||||||
|
Platform
|
||||||
|
</div>
|
||||||
|
<h1 className="mt-4 font-heading text-4xl font-bold tracking-tight sm:text-5xl">
|
||||||
|
Everything you need to ship
|
||||||
|
</h1>
|
||||||
|
<p className="mt-6 text-lg text-muted-foreground/80">
|
||||||
|
One integrated platform — no stitching together a dozen tools.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<FeaturesGrid />
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Deep Dives */}
|
||||||
|
<section className="border-t border-border/20 py-24 lg:py-32 bg-muted/10">
|
||||||
|
<div className="mx-auto max-w-6xl px-6 space-y-32">
|
||||||
|
|
||||||
|
{/* Git */}
|
||||||
|
<div className="grid lg:grid-cols-2 gap-12 items-center">
|
||||||
|
<div className="order-2 lg:order-1 rounded-2xl border border-border/30 bg-card p-2 shadow-2xl">
|
||||||
|
<div className="aspect-[4/3] rounded-xl bg-muted/30 flex flex-col p-6">
|
||||||
|
<div className="flex items-center gap-2 border-b border-border/30 pb-4">
|
||||||
|
<GitCommitHorizontal className="size-5 text-primary" />
|
||||||
|
<span className="font-mono text-sm font-semibold">commit history</span>
|
||||||
|
</div>
|
||||||
|
<div className="mt-4 space-y-4">
|
||||||
|
{[1,2,3].map(i => (
|
||||||
|
<div key={i} className="flex gap-4 items-center">
|
||||||
|
<div className="size-8 rounded-full bg-primary/20 shrink-0" />
|
||||||
|
<div className="space-y-1.5 flex-1">
|
||||||
|
<div className="h-3 w-3/4 bg-primary/20 rounded" />
|
||||||
|
<div className="h-2 w-1/4 bg-muted-foreground/20 rounded" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="order-1 lg:order-2 space-y-6">
|
||||||
|
<div className="inline-flex h-12 w-12 items-center justify-center rounded-xl bg-primary/10 text-primary">
|
||||||
|
<GitCommitHorizontal className="size-6" />
|
||||||
|
</div>
|
||||||
|
<h2 className="text-3xl font-bold font-heading">Enterprise-grade Git Hosting</h2>
|
||||||
|
<p className="text-lg text-muted-foreground/80 leading-relaxed">
|
||||||
|
Experience lightning-fast git operations. Branch, tag, and merge with confidence. Our architecture ensures your code is safe, accessible, and always available.
|
||||||
|
</p>
|
||||||
|
<ul className="space-y-3 text-muted-foreground">
|
||||||
|
<li className="flex items-center gap-3">✓ SSH and HTTPS cloning</li>
|
||||||
|
<li className="flex items-center gap-3">✓ Branch protection rules</li>
|
||||||
|
<li className="flex items-center gap-3">✓ Comprehensive audit logs</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Chat */}
|
||||||
|
<div className="grid lg:grid-cols-2 gap-12 items-center">
|
||||||
|
<div className="space-y-6">
|
||||||
|
<div className="inline-flex h-12 w-12 items-center justify-center rounded-xl bg-primary/10 text-primary">
|
||||||
|
<MessageSquare className="size-6" />
|
||||||
|
</div>
|
||||||
|
<h2 className="text-3xl font-bold font-heading">Contextual Conversations</h2>
|
||||||
|
<p className="text-lg text-muted-foreground/80 leading-relaxed">
|
||||||
|
Real-time channels integrated directly into your workflow. Discuss code, share files, and resolve issues without context switching.
|
||||||
|
</p>
|
||||||
|
<ul className="space-y-3 text-muted-foreground">
|
||||||
|
<li className="flex items-center gap-3">✓ Threaded conversations</li>
|
||||||
|
<li className="flex items-center gap-3">✓ Link unfurling for PRs & Issues</li>
|
||||||
|
<li className="flex items-center gap-3">✓ Voice and screen sharing</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div className="rounded-2xl border border-border/30 bg-card p-2 shadow-2xl">
|
||||||
|
<div className="aspect-[4/3] rounded-xl bg-muted/30 flex flex-col p-6">
|
||||||
|
<div className="flex items-center gap-2 border-b border-border/30 pb-4">
|
||||||
|
<MessageSquare className="size-5 text-primary" />
|
||||||
|
<span className="font-semibold text-sm"># engineering</span>
|
||||||
|
</div>
|
||||||
|
<div className="mt-4 space-y-4 flex-1 flex flex-col justify-end">
|
||||||
|
<div className="flex gap-3">
|
||||||
|
<div className="size-8 rounded bg-primary/20 shrink-0" />
|
||||||
|
<div className="bg-background rounded-2xl rounded-tl-none p-3 shadow-sm border border-border/50">
|
||||||
|
<div className="h-2 w-48 bg-muted-foreground/20 rounded mb-2" />
|
||||||
|
<div className="h-2 w-32 bg-muted-foreground/20 rounded" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-3 flex-row-reverse">
|
||||||
|
<div className="size-8 rounded bg-primary shrink-0" />
|
||||||
|
<div className="bg-primary text-primary-foreground rounded-2xl rounded-tr-none p-3 shadow-sm">
|
||||||
|
<div className="h-2 w-40 bg-primary-foreground/40 rounded mb-2" />
|
||||||
|
<div className="h-2 w-24 bg-primary-foreground/40 rounded" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* AI */}
|
||||||
|
<div className="grid lg:grid-cols-2 gap-12 items-center">
|
||||||
|
<div className="order-2 lg:order-1 rounded-2xl border border-border/30 bg-card p-2 shadow-2xl">
|
||||||
|
<div className="aspect-[4/3] rounded-xl bg-primary/5 flex flex-col items-center justify-center p-6 relative overflow-hidden">
|
||||||
|
<div className="absolute inset-0 bg-[radial-gradient(circle_at_center,var(--color-primary)_0,transparent_50%)] opacity-10 blur-xl" />
|
||||||
|
<Bot className="size-24 text-primary mb-6 animate-pulse" />
|
||||||
|
<div className="h-3 w-48 bg-primary/20 rounded mb-3" />
|
||||||
|
<div className="h-3 w-64 bg-primary/20 rounded" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="order-1 lg:order-2 space-y-6">
|
||||||
|
<div className="inline-flex h-12 w-12 items-center justify-center rounded-xl bg-primary/10 text-primary">
|
||||||
|
<Bot className="size-6" />
|
||||||
|
</div>
|
||||||
|
<h2 className="text-3xl font-bold font-heading">Intelligent Automation</h2>
|
||||||
|
<p className="text-lg text-muted-foreground/80 leading-relaxed">
|
||||||
|
Deploy autonomous agents that understand your codebase. Have them review PRs, triage issues, and answer questions.
|
||||||
|
</p>
|
||||||
|
<ul className="space-y-3 text-muted-foreground">
|
||||||
|
<li className="flex items-center gap-3">✓ Automated Code Review</li>
|
||||||
|
<li className="flex items-center gap-3">✓ Semantic Code Search</li>
|
||||||
|
<li className="flex items-center gap-3">✓ Smart Issue Triage</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-32 text-center">
|
||||||
|
<h2 className="text-2xl font-bold mb-8">Ready to experience it?</h2>
|
||||||
|
<Button asChild size="lg" className="h-11 px-8 shadow-lg shadow-primary/20">
|
||||||
|
<Link to="/auth/register">
|
||||||
|
Start building free
|
||||||
|
<ArrowRight className="ml-2 size-4" />
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
190
src/page/landing/home.tsx
Normal file
190
src/page/landing/home.tsx
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
import { Link } from "react-router";
|
||||||
|
import { ArrowRight } from "lucide-react";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import FeaturesGrid from "./features-grid";
|
||||||
|
import TerminalDemo from "@/components/landing/terminal-demo";
|
||||||
|
import DashboardMockup from "@/components/landing/dashboard-mockup";
|
||||||
|
import { GitBranch, Layers, MessageSquare, Bot } from "lucide-react";
|
||||||
|
|
||||||
|
export default function LandingHome() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* Hero */}
|
||||||
|
<section className="relative flex min-h-[88vh] items-center">
|
||||||
|
<div className="mx-auto w-full max-w-6xl px-6 py-24 lg:py-28">
|
||||||
|
<div className="mx-auto max-w-3xl text-center">
|
||||||
|
<div className="mx-auto mb-8 inline-flex items-center gap-2 rounded-full border border-primary/15 bg-primary/[0.03] px-4 py-1.5 text-xs font-medium text-primary/80">
|
||||||
|
<Layers className="size-3" />
|
||||||
|
The all-in-one developer platform
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1 className="text-balance font-heading text-5xl font-bold leading-[1.05] tracking-tight sm:text-6xl lg:text-7xl">
|
||||||
|
Build. Ship.{" "}
|
||||||
|
<span className="bg-gradient-to-r from-primary via-primary to-primary/40 bg-clip-text text-transparent">
|
||||||
|
With intelligence.
|
||||||
|
</span>
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<p className="mx-auto mt-6 max-w-lg text-balance text-lg leading-relaxed text-muted-foreground/80">
|
||||||
|
Git hosting, real-time collaboration, and AI agents — one platform
|
||||||
|
for modern dev teams who ship fast.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="mt-10 flex flex-wrap items-center justify-center gap-4">
|
||||||
|
<Button asChild size="lg" className="h-11 px-6 shadow-lg shadow-primary/20">
|
||||||
|
<Link to="/auth/register">
|
||||||
|
Start building free
|
||||||
|
<ArrowRight className="size-4" />
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
<Button asChild size="lg" variant="outline" className="h-11 px-6">
|
||||||
|
<Link to="/auth/login">Sign in</Link>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="mt-6 text-xs text-muted-foreground/45">
|
||||||
|
Free to start. No credit card required.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<DashboardMockup />
|
||||||
|
</div>
|
||||||
|
<div className="pointer-events-none absolute inset-x-0 bottom-0 h-40 bg-gradient-to-t from-background via-background/80 to-transparent" />
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Product loop */}
|
||||||
|
<section className="border-t border-border/20 bg-muted/[0.1] py-10">
|
||||||
|
<div className="mx-auto grid max-w-6xl gap-3 px-6 sm:grid-cols-3">
|
||||||
|
{[
|
||||||
|
{ label: "Git-native", value: "Repos, PRs, branches" },
|
||||||
|
{ label: "AI in context", value: "Review, triage, automate" },
|
||||||
|
{ label: "Team sync", value: "Channels tied to work" },
|
||||||
|
].map((item) => (
|
||||||
|
<div className="rounded-2xl border border-border/30 bg-card/70 px-5 py-4 text-center shadow-sm" key={item.label}>
|
||||||
|
<div className="font-heading text-sm font-semibold text-foreground">{item.label}</div>
|
||||||
|
<div className="mt-1 text-xs text-muted-foreground/70">{item.value}</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Features overview */}
|
||||||
|
<section className="border-t border-border/20 bg-muted/[0.1] py-24 lg:py-32">
|
||||||
|
<div className="mx-auto max-w-6xl px-6">
|
||||||
|
<div className="mx-auto mb-12 max-w-2xl text-center">
|
||||||
|
<h2 className="font-heading text-3xl font-bold tracking-tight">
|
||||||
|
Everything you need to ship
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<FeaturesGrid />
|
||||||
|
<div className="mt-10 text-center">
|
||||||
|
<Button asChild variant="outline">
|
||||||
|
<Link to="/features">
|
||||||
|
Explore all features
|
||||||
|
<ArrowRight className="size-4" />
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Workflow + Terminal */}
|
||||||
|
<section className="border-t border-border/20 py-24 lg:py-32">
|
||||||
|
<div className="mx-auto max-w-6xl px-6">
|
||||||
|
<div className="grid items-center gap-12 lg:grid-cols-2 lg:gap-20">
|
||||||
|
<div>
|
||||||
|
<div className="inline-flex items-center gap-2 rounded-full border border-border/60 bg-muted/50 px-3 py-1 text-xs font-medium text-muted-foreground">
|
||||||
|
<GitBranch className="size-3 text-primary" />
|
||||||
|
Workflow
|
||||||
|
</div>
|
||||||
|
<h2 className="mt-4 font-heading text-3xl font-bold tracking-tight">
|
||||||
|
Standard git, supercharged
|
||||||
|
</h2>
|
||||||
|
<p className="mt-4 text-muted-foreground/70">
|
||||||
|
Same workflow you know. AI reviews every PR. Channels keep your
|
||||||
|
team in sync. Deploy with confidence.
|
||||||
|
</p>
|
||||||
|
<div className="mt-6">
|
||||||
|
<Button asChild variant="outline">
|
||||||
|
<Link to="/workflow">
|
||||||
|
See how it works
|
||||||
|
<ArrowRight className="size-4" />
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<TerminalDemo />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Product fit */}
|
||||||
|
<section className="border-t border-border/20 bg-muted/[0.1] py-24 lg:py-32">
|
||||||
|
<div className="mx-auto max-w-6xl px-6">
|
||||||
|
<div className="mx-auto mb-16 max-w-2xl text-center">
|
||||||
|
<h2 className="font-heading text-3xl font-bold tracking-tight">
|
||||||
|
One workspace for code, agents, and discussion
|
||||||
|
</h2>
|
||||||
|
<p className="mt-4 text-muted-foreground/70">
|
||||||
|
The interface mirrors the app itself: repository work on the left,
|
||||||
|
live context in channels, and AI assistance close to every task.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="grid gap-6 md:grid-cols-3">
|
||||||
|
{[
|
||||||
|
{
|
||||||
|
icon: GitBranch,
|
||||||
|
title: "Trace work to code",
|
||||||
|
desc: "Repositories, issues, pull requests, and commits stay in the same workspace structure.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: MessageSquare,
|
||||||
|
title: "Discuss with context",
|
||||||
|
desc: "Channels keep team decisions next to the repositories and workplans they affect.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Bot,
|
||||||
|
title: "Bring agents into flow",
|
||||||
|
desc: "AI review and automation live beside human collaboration instead of in a separate tool.",
|
||||||
|
},
|
||||||
|
].map((item) => (
|
||||||
|
<div key={item.title} className="rounded-2xl border border-border/30 bg-card p-8 shadow-sm">
|
||||||
|
<div className="grid size-11 place-items-center rounded-xl bg-primary/10 text-primary">
|
||||||
|
<item.icon className="size-5" />
|
||||||
|
</div>
|
||||||
|
<h3 className="mt-5 font-heading text-base font-semibold">{item.title}</h3>
|
||||||
|
<p className="mt-2 text-[13px] leading-relaxed text-muted-foreground/70">{item.desc}</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Bottom CTA */}
|
||||||
|
<section className="border-t border-border/20 py-24 lg:py-32">
|
||||||
|
<div className="mx-auto max-w-6xl px-6">
|
||||||
|
<div className="relative overflow-hidden rounded-3xl border border-border/20 bg-gradient-to-br from-primary/[0.05] via-primary/[0.01] to-transparent p-12 text-center shadow-2xl shadow-primary/[0.02] lg:p-16">
|
||||||
|
<div className="pointer-events-none absolute -right-16 -top-16 size-64 rounded-full bg-primary/[0.03] blur-[100px]" />
|
||||||
|
<h2 className="relative font-heading text-3xl font-bold tracking-tight">
|
||||||
|
Ready to ship faster?
|
||||||
|
</h2>
|
||||||
|
<p className="relative mt-4 text-muted-foreground/60">
|
||||||
|
Join teams using GitDataAI to build better software, together.
|
||||||
|
</p>
|
||||||
|
<div className="relative mt-8 flex items-center justify-center gap-4">
|
||||||
|
<Button asChild size="lg" className="h-11 px-6 shadow-lg shadow-primary/20">
|
||||||
|
<Link to="/auth/register">
|
||||||
|
Get started free
|
||||||
|
<ArrowRight className="size-4" />
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
<Button asChild size="lg" variant="outline" className="h-11 px-6">
|
||||||
|
<Link to="/auth/login">Sign in</Link>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
36
src/page/landing/layout.tsx
Normal file
36
src/page/landing/layout.tsx
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { useEffect } from "react";
|
||||||
|
import { Outlet, useNavigate } from "react-router";
|
||||||
|
import { Loader2 } from "lucide-react";
|
||||||
|
import { useAuth } from "@/context/auth-context";
|
||||||
|
import AmbientLight from "@/components/landing/ambient-light";
|
||||||
|
import Header from "@/components/landing/header";
|
||||||
|
import Footer from "@/components/landing/footer";
|
||||||
|
|
||||||
|
export default function LandingLayout() {
|
||||||
|
const { isAuthenticated, isLoading } = useAuth();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isLoading && isAuthenticated) navigate("/me", { replace: true });
|
||||||
|
}, [isAuthenticated, isLoading, navigate]);
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return (
|
||||||
|
<div className="flex h-screen items-center justify-center bg-background">
|
||||||
|
<Loader2 className="size-5 animate-spin text-muted-foreground/30" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (isAuthenticated) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="relative min-h-screen overflow-x-hidden bg-background font-sans antialiased">
|
||||||
|
<AmbientLight />
|
||||||
|
<Header />
|
||||||
|
<main className="min-h-[60vh]">
|
||||||
|
<Outlet />
|
||||||
|
</main>
|
||||||
|
<Footer />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
193
src/page/landing/pricing.tsx
Normal file
193
src/page/landing/pricing.tsx
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
import { Link } from "react-router";
|
||||||
|
import { CheckCircle2, XCircle } from "lucide-react";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
|
||||||
|
const plans = [
|
||||||
|
{
|
||||||
|
name: "Free",
|
||||||
|
price: "$0",
|
||||||
|
period: "forever",
|
||||||
|
desc: "For individuals and small teams getting started.",
|
||||||
|
features: [
|
||||||
|
"Unlimited public repositories",
|
||||||
|
"5 private repositories",
|
||||||
|
"Real-time channels",
|
||||||
|
"Community support",
|
||||||
|
"1 GB storage",
|
||||||
|
],
|
||||||
|
cta: "Get started free",
|
||||||
|
href: "/auth/register",
|
||||||
|
primary: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Pro",
|
||||||
|
price: "$12",
|
||||||
|
period: "/ month",
|
||||||
|
desc: "For growing teams that need more power.",
|
||||||
|
features: [
|
||||||
|
"Unlimited private repositories",
|
||||||
|
"AI code review agents",
|
||||||
|
"Voice channels",
|
||||||
|
"Priority support",
|
||||||
|
"50 GB storage",
|
||||||
|
"Advanced analytics",
|
||||||
|
],
|
||||||
|
cta: "Start Pro trial",
|
||||||
|
href: "/auth/register",
|
||||||
|
primary: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Enterprise",
|
||||||
|
price: "Custom",
|
||||||
|
period: "",
|
||||||
|
desc: "For large organizations with custom needs.",
|
||||||
|
features: [
|
||||||
|
"Everything in Pro",
|
||||||
|
"SSO & SAML",
|
||||||
|
"Audit logs",
|
||||||
|
"Dedicated support",
|
||||||
|
"Unlimited storage",
|
||||||
|
"Custom integrations",
|
||||||
|
"On-premise option",
|
||||||
|
],
|
||||||
|
cta: "Contact sales",
|
||||||
|
href: "/auth/register",
|
||||||
|
primary: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const compareFeatures = [
|
||||||
|
{ name: "Public Repositories", free: true, pro: true, ent: true },
|
||||||
|
{ name: "Private Repositories", free: "5", pro: "Unlimited", ent: "Unlimited" },
|
||||||
|
{ name: "Storage", free: "1 GB", pro: "50 GB", ent: "Unlimited" },
|
||||||
|
{ name: "Real-time Channels", free: true, pro: true, ent: true },
|
||||||
|
{ name: "Voice Channels", free: false, pro: true, ent: true },
|
||||||
|
{ name: "AI Code Review", free: false, pro: true, ent: true },
|
||||||
|
{ name: "Custom AI Agents", free: false, pro: "3 included", ent: "Unlimited" },
|
||||||
|
{ name: "SSO & SAML", free: false, pro: false, ent: true },
|
||||||
|
{ name: "Audit Logs", free: false, pro: false, ent: true },
|
||||||
|
{ name: "Support", free: "Community", pro: "Priority", ent: "Dedicated" },
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function PricingPage() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<section className="py-24 lg:py-32">
|
||||||
|
<div className="mx-auto max-w-6xl px-6">
|
||||||
|
<div className="mx-auto mb-16 max-w-2xl text-center">
|
||||||
|
<h1 className="font-heading text-4xl font-bold tracking-tight sm:text-5xl">
|
||||||
|
Simple, transparent pricing
|
||||||
|
</h1>
|
||||||
|
<p className="mt-6 text-lg text-muted-foreground/80">
|
||||||
|
Start for free. Upgrade when you need more. No hidden fees.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid gap-6 lg:grid-cols-3">
|
||||||
|
{plans.map((p) => (
|
||||||
|
<div
|
||||||
|
className={`relative flex flex-col rounded-3xl border p-8 transition-transform hover:-translate-y-1 ${
|
||||||
|
p.primary
|
||||||
|
? "border-primary/30 bg-primary/[0.03] shadow-2xl shadow-primary/[0.05] ring-1 ring-primary/10"
|
||||||
|
: "border-border/40 bg-card/50 shadow-lg backdrop-blur"
|
||||||
|
}`}
|
||||||
|
key={p.name}
|
||||||
|
>
|
||||||
|
{p.primary && (
|
||||||
|
<div className="absolute -top-3 left-1/2 -translate-x-1/2 rounded-full bg-gradient-to-r from-primary to-primary/80 px-4 py-1 text-xs font-bold text-primary-foreground shadow-sm">
|
||||||
|
Most popular
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<h3 className="font-heading text-xl font-bold">{p.name}</h3>
|
||||||
|
<div className="mt-4 flex items-baseline gap-1">
|
||||||
|
<span className="font-heading text-5xl font-bold tracking-tight">
|
||||||
|
{p.price}
|
||||||
|
</span>
|
||||||
|
{p.period && (
|
||||||
|
<span className="text-sm font-medium text-muted-foreground/70">
|
||||||
|
{p.period}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<p className="mt-4 text-sm text-muted-foreground/80 leading-relaxed min-h-[40px]">{p.desc}</p>
|
||||||
|
|
||||||
|
<ul className="mt-8 flex-1 space-y-4">
|
||||||
|
{p.features.map((f) => (
|
||||||
|
<li className="flex items-start gap-3 text-sm" key={f}>
|
||||||
|
<CheckCircle2 className="mt-0.5 size-4 shrink-0 text-primary" />
|
||||||
|
<span className="text-foreground/90 font-medium">{f}</span>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
asChild
|
||||||
|
className={`mt-10 h-11 w-full ${p.primary ? 'shadow-lg shadow-primary/20' : ''}`}
|
||||||
|
variant={p.primary ? "default" : "outline"}
|
||||||
|
>
|
||||||
|
<Link to={p.href}>
|
||||||
|
{p.cta}
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Feature Comparison */}
|
||||||
|
<section className="py-24 border-t border-border/20 bg-muted/10">
|
||||||
|
<div className="mx-auto max-w-5xl px-6">
|
||||||
|
<h2 className="text-3xl font-bold font-heading text-center mb-12">Compare features</h2>
|
||||||
|
<div className="overflow-x-auto">
|
||||||
|
<table className="w-full text-left border-collapse">
|
||||||
|
<thead>
|
||||||
|
<tr className="border-b border-border/40">
|
||||||
|
<th className="p-4 font-semibold text-muted-foreground w-1/3">Feature</th>
|
||||||
|
<th className="p-4 font-bold text-center w-2/9">Free</th>
|
||||||
|
<th className="p-4 font-bold text-center w-2/9 text-primary">Pro</th>
|
||||||
|
<th className="p-4 font-bold text-center w-2/9">Enterprise</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody className="divide-y divide-border/20">
|
||||||
|
{compareFeatures.map((f, i) => (
|
||||||
|
<tr key={i} className="hover:bg-muted/30 transition-colors">
|
||||||
|
<td className="p-4 text-sm font-medium text-foreground/80">{f.name}</td>
|
||||||
|
<td className="p-4 text-center">
|
||||||
|
{typeof f.free === 'boolean' ? (f.free ? <CheckCircle2 className="size-4 text-primary mx-auto" /> : <XCircle className="size-4 text-muted-foreground/30 mx-auto" />) : <span className="text-sm font-medium">{f.free}</span>}
|
||||||
|
</td>
|
||||||
|
<td className="p-4 text-center bg-primary/[0.02]">
|
||||||
|
{typeof f.pro === 'boolean' ? (f.pro ? <CheckCircle2 className="size-4 text-primary mx-auto" /> : <XCircle className="size-4 text-muted-foreground/30 mx-auto" />) : <span className="text-sm font-bold text-primary">{f.pro}</span>}
|
||||||
|
</td>
|
||||||
|
<td className="p-4 text-center">
|
||||||
|
{typeof f.ent === 'boolean' ? (f.ent ? <CheckCircle2 className="size-4 text-primary mx-auto" /> : <XCircle className="size-4 text-muted-foreground/30 mx-auto" />) : <span className="text-sm font-medium">{f.ent}</span>}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* FAQ */}
|
||||||
|
<section className="py-24 border-t border-border/20">
|
||||||
|
<div className="mx-auto max-w-3xl px-6">
|
||||||
|
<h2 className="text-3xl font-bold font-heading text-center mb-12">Frequently asked questions</h2>
|
||||||
|
<div className="space-y-6">
|
||||||
|
{[
|
||||||
|
{ q: "Can I use GitDataAI for free?", a: "Yes, our Free plan gives you everything you need to get started, including unlimited public repos, 5 private repos, and core channel features." },
|
||||||
|
{ q: "How do AI agents work?", a: "AI agents are built into the platform. You can invite them to PRs for automatic code review, or @mention them in channels to answer questions based on your codebase context." },
|
||||||
|
{ q: "Do you offer an on-premise version?", a: "Yes, GitDataAI Enterprise can be deployed on your own infrastructure (AWS, GCP, Azure, or bare metal). Contact our sales team for details." }
|
||||||
|
].map((faq, i) => (
|
||||||
|
<div key={i} className="border border-border/30 rounded-xl p-6 bg-card">
|
||||||
|
<h4 className="font-bold text-lg">{faq.q}</h4>
|
||||||
|
<p className="mt-2 text-muted-foreground/80 leading-relaxed">{faq.a}</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
109
src/page/landing/workflow.tsx
Normal file
109
src/page/landing/workflow.tsx
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
import { Link } from "react-router";
|
||||||
|
import { ArrowRight, GitBranch, ArrowDown } from "lucide-react";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import TerminalDemo from "@/components/landing/terminal-demo";
|
||||||
|
|
||||||
|
const steps = [
|
||||||
|
{
|
||||||
|
title: "1. Create a workspace",
|
||||||
|
desc: "Set up a workspace for your team and invite members. Public or private — you decide.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "2. Push code",
|
||||||
|
desc: "Clone repositories via SSH or HTTPS. Push branches, create tags. Standard git, nothing new to learn.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "3. Open pull requests",
|
||||||
|
desc: "Create PRs with descriptions and reviewers. AI agents automatically review code for common issues.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "4. Collaborate in channels",
|
||||||
|
desc: "Discuss PRs and issues in real-time channels. Threads keep conversations organized. Voice channels for live reviews.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "5. Ship with confidence",
|
||||||
|
desc: "Merge, tag releases, and deploy. Webhooks integrate with your CI/CD pipeline. Monitor everything.",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function WorkflowPage() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<section className="py-24 lg:py-32">
|
||||||
|
<div className="mx-auto max-w-6xl px-6">
|
||||||
|
<div className="mx-auto mb-16 max-w-2xl text-center">
|
||||||
|
<div className="inline-flex items-center gap-2 rounded-full border border-border/60 bg-muted/50 px-3 py-1 text-xs font-medium text-muted-foreground">
|
||||||
|
<GitBranch className="size-3 text-primary" />
|
||||||
|
Workflow
|
||||||
|
</div>
|
||||||
|
<h1 className="mt-4 font-heading text-4xl font-bold tracking-tight sm:text-5xl">
|
||||||
|
From idea to production
|
||||||
|
</h1>
|
||||||
|
<p className="mt-6 text-lg text-muted-foreground/80">
|
||||||
|
Five steps to ship your next feature. Same tools you know, better together.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid items-start gap-16 lg:grid-cols-2 lg:gap-24 mt-20">
|
||||||
|
{/* Steps */}
|
||||||
|
<div className="relative border-l-2 border-primary/20 pl-8 space-y-12">
|
||||||
|
{steps.map((s, i) => (
|
||||||
|
<div className="relative" key={s.title}>
|
||||||
|
<span className="absolute -left-[43px] top-1 flex size-5 items-center justify-center rounded-full bg-primary text-[10px] font-bold text-primary-foreground ring-4 ring-background">
|
||||||
|
{i + 1}
|
||||||
|
</span>
|
||||||
|
<h3 className="font-heading text-xl font-bold">
|
||||||
|
{s.title}
|
||||||
|
</h3>
|
||||||
|
<p className="mt-3 text-[15px] leading-relaxed text-muted-foreground/80">
|
||||||
|
{s.desc}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Visuals */}
|
||||||
|
<div className="lg:sticky lg:top-32 space-y-8">
|
||||||
|
<TerminalDemo />
|
||||||
|
|
||||||
|
<div className="rounded-2xl border border-border/30 bg-card p-6 shadow-xl">
|
||||||
|
<div className="flex items-center gap-3 border-b border-border/30 pb-4 mb-4">
|
||||||
|
<div className="size-10 rounded-xl bg-primary/10 flex items-center justify-center text-primary">
|
||||||
|
<ArrowDown className="size-5" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="font-semibold text-sm">Automated CI/CD Pipeline</div>
|
||||||
|
<div className="text-xs text-muted-foreground">Triggered on merge to main</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-3">
|
||||||
|
<div className="flex justify-between text-xs p-2 rounded bg-muted/30">
|
||||||
|
<span className="font-mono text-muted-foreground">Lint & Format</span>
|
||||||
|
<span className="text-emerald-500">Success</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between text-xs p-2 rounded bg-muted/30">
|
||||||
|
<span className="font-mono text-muted-foreground">Unit Tests</span>
|
||||||
|
<span className="text-emerald-500">Success</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between text-xs p-2 rounded bg-primary/5 border border-primary/20">
|
||||||
|
<span className="font-mono text-primary font-medium">Deploy to Production</span>
|
||||||
|
<span className="animate-pulse text-primary">Running…</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-24 text-center">
|
||||||
|
<Button asChild size="lg" className="h-11 px-8 shadow-lg shadow-primary/20">
|
||||||
|
<Link to="/auth/register">
|
||||||
|
Start building free
|
||||||
|
<ArrowRight className="ml-2 size-4" />
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user