kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
feat: marketing page work
rodzic
33e943a441
commit
a42ea77ff2
|
@ -1,7 +1,6 @@
|
|||
import './globals.css'
|
||||
|
||||
import type { Metadata } from 'next'
|
||||
import cs from 'clsx'
|
||||
import { Geist } from 'next/font/google'
|
||||
import { Toaster } from 'sonner'
|
||||
|
||||
|
@ -11,7 +10,6 @@ import { Header } from '@/components/header'
|
|||
import * as config from '@/lib/config'
|
||||
|
||||
import Providers from './providers'
|
||||
import styles from './styles.module.css'
|
||||
|
||||
const geist = Geist({
|
||||
variable: '--font-geist',
|
||||
|
@ -49,10 +47,10 @@ export default function RootLayout({
|
|||
<html lang='en' suppressHydrationWarning>
|
||||
<body className={`${geist.variable} antialiased`}>
|
||||
<Providers>
|
||||
<div className={styles.root}>
|
||||
<div className='w-full min-h-[100vh] relative flex flex-col items-center'>
|
||||
<Header />
|
||||
|
||||
<main className={cs(styles.main, 'pt-8 pb-16 px-4 md:px-0')}>
|
||||
<main className='flex-1 w-full flex flex-col items-center max-w-[1200px] gap-16 pt-8 pb-16 px-4 md:px-0'>
|
||||
{children}
|
||||
</main>
|
||||
|
||||
|
|
|
@ -1,9 +1,19 @@
|
|||
import { OpenSourceSection } from '@/components/open-source-section'
|
||||
import { SupplySideCTA } from '@/components/supply-side-cta'
|
||||
import Link from 'next/link'
|
||||
|
||||
export default function IndexPage() {
|
||||
import { GitHubStarCounter } from '@/components/github-star-counter'
|
||||
import { SupplySideCTA } from '@/components/supply-side-cta'
|
||||
import {
|
||||
calendarBookingUrl,
|
||||
discordUrl,
|
||||
docsUrl,
|
||||
githubUrl,
|
||||
twitterUrl
|
||||
} from '@/lib/config'
|
||||
|
||||
export default function TheBestDamnLandingPageEver() {
|
||||
return (
|
||||
<>
|
||||
{/* Hero section */}
|
||||
<section className='gap-8'>
|
||||
<h1 className='text-center text-balance leading-snug md:leading-none text-4xl font-extrabold'>
|
||||
Your API → Paid MCP, Instantly
|
||||
|
@ -18,13 +28,208 @@ export default function IndexPage() {
|
|||
<SupplySideCTA />
|
||||
</section>
|
||||
|
||||
<section className='flex-1'>
|
||||
<h2 className='text-center text-balance text-lg'>How it works</h2>
|
||||
{/* How it works section */}
|
||||
<section className='flex flex-col gap-8'>
|
||||
<h2 className='text-center text-balance leading-snug md:leading-none text-2xl font-heading'>
|
||||
How It Works
|
||||
</h2>
|
||||
|
||||
<div>TODO</div>
|
||||
</section>
|
||||
|
||||
<OpenSourceSection />
|
||||
{/* Features section */}
|
||||
<section className='flex flex-col gap-8'>
|
||||
<h2 className='text-center text-balance leading-snug md:leading-none text-2xl font-heading'>
|
||||
Production-Ready and Extremely Flexible
|
||||
</h2>
|
||||
|
||||
<div className='grid gap-6'>
|
||||
<div className='flex flex-col gap-2'>
|
||||
<h4 className='text-center text-balance text-lg font-heading'>
|
||||
Auth
|
||||
</h4>
|
||||
|
||||
<p className='text-sm'>
|
||||
Ship to production fast with Agentic's free, built-in
|
||||
authentication. Email & password, OAuth, GitHub, Google, Twitter,
|
||||
etc – if your origin API requires OAuth credentials, Agentic
|
||||
likely already supports it, and if not,{' '}
|
||||
<Link
|
||||
href={calendarBookingUrl}
|
||||
target='_blank'
|
||||
rel='noopener'
|
||||
className='link'
|
||||
>
|
||||
let me know
|
||||
</Link>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col gap-2'>
|
||||
<h4 className='text-center text-balance text-lg font-heading'>
|
||||
Monetization
|
||||
</h4>
|
||||
|
||||
<p className='text-sm'>
|
||||
Charge for your MCP products with a flexible, declarative pricing
|
||||
model built on top of Stripe. Agentic supports almost any
|
||||
combination of fixed and usage-based billing models, both at the
|
||||
MCP level, at the tool-call level, and at the custom metric level
|
||||
(e.g., tokens, image transformations, etc).
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col gap-2'>
|
||||
<h4 className='text-center text-balance text-lg font-heading'>
|
||||
Support both MCP <em>and</em> HTTP
|
||||
</h4>
|
||||
|
||||
<p className='text-sm'>
|
||||
All agentic products support being used both as a standard MCP
|
||||
server <em>and</em> as an extremely simple HTTP API. MCP is
|
||||
important for interop, discoverability, and future-proofing,
|
||||
whereas being able to call your agentic tools via simple{' '}
|
||||
<em>HTTP POST</em> requests makes tool use easy to debug and makes
|
||||
integration with existing LLM tool calling patterns a breeze. With
|
||||
Agentic, you get the best of both worlds, including future support
|
||||
for unreleased MCP features and related specs.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col gap-2'>
|
||||
<h4 className='text-center text-balance text-lg font-heading'>
|
||||
Rate-limiting
|
||||
</h4>
|
||||
|
||||
<p className='text-sm'>
|
||||
Customize your MCP product with durable rate-limiting built on top
|
||||
of Cloudflare's global infrastructure. Create default rate-limits,
|
||||
change them based on a customer's subscribed pricing plan, and
|
||||
create custom tool-specific overrides, all with a simple,
|
||||
strongly-typed JSON config. REST assured that your origin API will
|
||||
be safe behind Agentic's robust API gateway.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col gap-2'>
|
||||
<h4 className='text-center text-balance text-lg font-heading'>
|
||||
Caching
|
||||
</h4>
|
||||
|
||||
<p className='text-sm'>
|
||||
Opt-in to caching with familiar <em>cache-control</em> and{' '}
|
||||
<em>stale-while-revalidate</em> features. MCP tool calls include
|
||||
caching information in their <em>_meta</em> fields with symmetry
|
||||
to standard HTTP headers. All caching takes place in Cloudflare's
|
||||
global edge cache, and will only be enabled if you choose to
|
||||
enable it for your product or specific tools.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col gap-2'>
|
||||
<h4 className='text-center text-balance text-lg font-heading'>
|
||||
Analytics
|
||||
</h4>
|
||||
|
||||
<p className='text-sm'>
|
||||
Agentic tracks usage-based billing and analytics at a fine-grained
|
||||
level, so you can understand how your customers are using your
|
||||
product.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col gap-2'>
|
||||
<h4 className='text-center text-balance text-lg font-heading'>
|
||||
Versioning
|
||||
</h4>
|
||||
|
||||
<p className='text-sm'>
|
||||
Just like Vercel, Agentic uses immutable deployments, so every
|
||||
time you make a change to your product's config, pricing, or docs,
|
||||
a unique preview deployment is created for that change. This
|
||||
enables instant rollbacks if there are problems with a deployment.
|
||||
Publish deployment publicly uses semantic versioning (
|
||||
<em>semver</em>), so your customers can choose how to handle
|
||||
breaking changes.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col gap-2'>
|
||||
<h4 className='text-center text-balance text-lg font-heading'>
|
||||
And more!
|
||||
</h4>
|
||||
|
||||
<p className='text-sm'>
|
||||
Checkout our <Link href={docsUrl}>docs</Link> for more details on
|
||||
Agentic's MCP API gateway.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Marketplace section */}
|
||||
<section className='flex flex-col gap-8'>
|
||||
<h2 className='text-center text-balance leading-snug md:leading-none text-2xl font-heading'>
|
||||
MCP Marketplace
|
||||
</h2>
|
||||
|
||||
<p>Coming soon...</p>
|
||||
</section>
|
||||
|
||||
{/* Open source section */}
|
||||
<section className='flex flex-col items-center gap-8 max-w-2xl text-center'>
|
||||
<h2 className='text-center text-balance leading-snug md:leading-none text-2xl font-heading italic'>
|
||||
Agentic is 100% Open Source!
|
||||
</h2>
|
||||
|
||||
<p className='text-sm'>
|
||||
Join the tens of thousands of TypeScript AI engineers who've{' '}
|
||||
<Link
|
||||
href={githubUrl}
|
||||
target='_blank'
|
||||
rel='noopener'
|
||||
className='link'
|
||||
>
|
||||
starred the project on GitHub
|
||||
</Link>
|
||||
.{' '}
|
||||
<Link
|
||||
href={githubUrl}
|
||||
target='_blank'
|
||||
rel='noopener'
|
||||
className='link'
|
||||
>
|
||||
Check out the source on GitHub
|
||||
</Link>
|
||||
,{' '}
|
||||
<Link
|
||||
href={discordUrl}
|
||||
target='_blank'
|
||||
rel='noopener'
|
||||
className='link'
|
||||
>
|
||||
join our community on Discord
|
||||
</Link>
|
||||
, or{' '}
|
||||
<Link
|
||||
href={twitterUrl}
|
||||
target='_blank'
|
||||
rel='noopener'
|
||||
className='link'
|
||||
>
|
||||
ping me on Twitter
|
||||
</Link>
|
||||
.
|
||||
</p>
|
||||
|
||||
<GitHubStarCounter />
|
||||
</section>
|
||||
|
||||
{/* CTA section */}
|
||||
<section className='flex flex-col gap-8'>
|
||||
<SupplySideCTA />
|
||||
</section>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
.root {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.main {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
max-width: 1200px;
|
||||
}
|
|
@ -4,6 +4,8 @@ import type { Simplify } from 'type-fest'
|
|||
import confetti, { type Options as ConfettiBaseOptions } from 'canvas-confetti'
|
||||
import { useCallback } from 'react'
|
||||
|
||||
import { randomInRange } from '@/lib/utils'
|
||||
|
||||
export type ConfettiOptions = Simplify<
|
||||
ConfettiBaseOptions & {
|
||||
duration?: number
|
||||
|
@ -55,7 +57,3 @@ export function useConfettiFireworks() {
|
|||
fireConfetti
|
||||
}
|
||||
}
|
||||
|
||||
function randomInRange(min: number, max: number) {
|
||||
return Math.random() * (max - min) + min
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ export function Footer() {
|
|||
<div className='flex flex-col md:items-center'>
|
||||
<div className='space-y-4'>
|
||||
<h3 className='text-lg font-semibold'>Site</h3>
|
||||
|
||||
<nav className='flex flex-col space-y-2'>
|
||||
<span>
|
||||
<ActiveLink href='/' className='link'>
|
||||
|
@ -38,16 +39,18 @@ export function Footer() {
|
|||
<div className='flex flex-col order-last md:order-none col-span-2'>
|
||||
<div className='space-y-4 flex flex-col w-full'>
|
||||
<h3 className='text-lg font-semibold'>TODO</h3>
|
||||
|
||||
<div className='grid grid-cols-[repeat(auto-fill,_minmax(10em,_1fr))] gap-y-4 gap-x-8 w-full flex-auto'>
|
||||
<div className='link'>TODO</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col md:items-center'>
|
||||
<div className='flex flex-col md:items-center gap-4'>
|
||||
<div className='space-y-4'>
|
||||
<h3 className='text-lg font-semibold'>Social</h3>
|
||||
<nav className='flex flex-col space-y-2'>
|
||||
|
||||
<nav className='flex flex-col gap-4'>
|
||||
<Link
|
||||
href={twitterUrl}
|
||||
className='flex items-center space-x-2'
|
||||
|
|
|
@ -6,22 +6,28 @@ import { useEffect, useState } from 'react'
|
|||
|
||||
import { GitHubIcon } from '@/icons/github'
|
||||
import { githubUrl } from '@/lib/config'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
import { Button } from './ui/button'
|
||||
|
||||
// TODO: fetch this dynamically
|
||||
const numGitHubStars = 17_600
|
||||
|
||||
export function GitHubStarCounter() {
|
||||
export function GitHubStarCounter({ className }: { className?: string }) {
|
||||
const [numStars, setNumStars] = useState(0)
|
||||
|
||||
useEffect(() => {
|
||||
setNumStars(numGitHubStars)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Button variant='outline' className='flex items-center gap-2' asChild>
|
||||
<Button
|
||||
variant='outline'
|
||||
className={cn('flex items-center gap-2', className)}
|
||||
asChild
|
||||
>
|
||||
<Link href={githubUrl} target='_blank' rel='noopener'>
|
||||
<GitHubIcon className='' />
|
||||
<GitHubIcon />
|
||||
|
||||
<NumberFlow
|
||||
value={numStars}
|
||||
|
@ -30,6 +36,7 @@ export function GitHubStarCounter() {
|
|||
roundingPriority: 'morePrecision'
|
||||
}}
|
||||
suffix=' stars'
|
||||
willChange
|
||||
/>
|
||||
</Link>
|
||||
</Button>
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
import { GitHubStarCounter } from './github-star-counter'
|
||||
|
||||
export function OpenSourceSection() {
|
||||
return (
|
||||
<section className='flex flex-col items-center gap-8'>
|
||||
<h2 className='text-center text-balance leading-snug md:leading-none text-2xl font-heading italic'>
|
||||
Agentic is 100% open source
|
||||
</h2>
|
||||
|
||||
<GitHubStarCounter />
|
||||
</section>
|
||||
)
|
||||
}
|
|
@ -1,14 +1,29 @@
|
|||
'use client'
|
||||
|
||||
import { sanitizeSearchParams } from '@agentic/platform-core'
|
||||
import Link from 'next/link'
|
||||
|
||||
import { HeroButton } from '@/components/hero-button'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { calendarBookingUrl, docsQuickStartUrl } from '@/lib/config'
|
||||
|
||||
import { useAgentic } from './agentic-provider'
|
||||
|
||||
export function SupplySideCTA() {
|
||||
const ctx = useAgentic()
|
||||
|
||||
return (
|
||||
<div className='flex justify-center items-center gap-8'>
|
||||
<HeroButton asChild className='h-full'>
|
||||
<Link href={docsQuickStartUrl}>Get Started</Link>
|
||||
<Link
|
||||
href={
|
||||
ctx?.isAuthenticated
|
||||
? docsQuickStartUrl
|
||||
: `/signup?${sanitizeSearchParams({ next: docsQuickStartUrl })}`
|
||||
}
|
||||
>
|
||||
Get Started
|
||||
</Link>
|
||||
</HeroButton>
|
||||
|
||||
<Button variant='outline' asChild className='h-full'>
|
||||
|
|
|
@ -21,6 +21,7 @@ export const calendarBookingUrl =
|
|||
export const docsUrl = 'https://docs.agentic.so'
|
||||
export const docsQuickStartUrl = `${docsUrl}/quick-start`
|
||||
export const docsMarketplaceUrl = `${docsUrl}/marketplace`
|
||||
export const discordUrl = 'https://discord.agentic.so'
|
||||
|
||||
export const keywords = [
|
||||
'agentic',
|
||||
|
|
|
@ -4,3 +4,7 @@ import { twMerge } from 'tailwind-merge'
|
|||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
||||
|
||||
export function randomInRange(min: number, max: number) {
|
||||
return Math.random() * (max - min) + min
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
- stripe checkout for changing plans? (need to at least be able to upgrade)
|
||||
- stripe billing portal
|
||||
- should we bypass stripe for `free` plans to increase conversions?
|
||||
- handle browser back/forward with `?next=`
|
||||
- **API gateway**
|
||||
- oauth flow
|
||||
- https://docs.scalekit.com/guides/mcp/oauth
|
||||
|
|
Ładowanie…
Reference in New Issue