kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
feat(web): finesse features section
rodzic
422da87f1c
commit
52302243cd
|
@ -2,14 +2,10 @@ import Link from 'next/link'
|
||||||
|
|
||||||
import { DotsSection } from '@/components/dots-section'
|
import { DotsSection } from '@/components/dots-section'
|
||||||
import { ExampleAgenticConfigs } from '@/components/example-agentic-configs'
|
import { ExampleAgenticConfigs } from '@/components/example-agentic-configs'
|
||||||
|
import { Features } from '@/components/features'
|
||||||
import { GitHubStarCounter } from '@/components/github-star-counter'
|
import { GitHubStarCounter } from '@/components/github-star-counter'
|
||||||
import { SupplySideCTA } from '@/components/supply-side-cta'
|
import { SupplySideCTA } from '@/components/supply-side-cta'
|
||||||
import {
|
import { githubUrl, twitterUrl } from '@/lib/config'
|
||||||
calendarBookingUrl,
|
|
||||||
docsUrl,
|
|
||||||
githubUrl,
|
|
||||||
twitterUrl
|
|
||||||
} from '@/lib/config'
|
|
||||||
|
|
||||||
export default function MCPAuthorsPage() {
|
export default function MCPAuthorsPage() {
|
||||||
return (
|
return (
|
||||||
|
@ -64,147 +60,10 @@ export default function MCPAuthorsPage() {
|
||||||
{/* Features section */}
|
{/* Features section */}
|
||||||
<section className='flex flex-col gap-8 mb-16'>
|
<section className='flex flex-col gap-8 mb-16'>
|
||||||
<h2 className='text-center text-balance leading-snug md:leading-none text-3xl font-heading'>
|
<h2 className='text-center text-balance leading-snug md:leading-none text-3xl font-heading'>
|
||||||
Production-Ready and Extremely Flexible
|
Production-Ready MCP Gateway
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<div className='grid gap-6 max-w-2xl'>
|
<Features />
|
||||||
<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'>
|
|
||||||
Stripe Billing
|
|
||||||
</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{' '}
|
|
||||||
<span className='font-semibold'>usage-based billing</span> 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 and 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'>
|
|
||||||
API keys
|
|
||||||
</h4>
|
|
||||||
|
|
||||||
<p className='text-sm'>
|
|
||||||
When a customer subscribes to your product, they're given a unique
|
|
||||||
API key. MCP URLs are appended with this API key to correlate
|
|
||||||
usage with their subscription. Customer HTTP tool calls use the
|
|
||||||
same API key as a standard HTTP <em>Authorization</em> header.
|
|
||||||
</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'>
|
|
||||||
All agentic products are protected by durable rate-limiting built
|
|
||||||
on top of Cloudflare's global infrastructure. Customize the
|
|
||||||
default rate-limits, change them based on a customer's pricing
|
|
||||||
plan, or create custom tool-specific overrides. 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> options. MCP tool calls include
|
|
||||||
caching information in their <em>_meta</em> fields, providing
|
|
||||||
parity with standard HTTP headers. All caching takes place in
|
|
||||||
Cloudflare's global edge cache, and caching will only be enabled
|
|
||||||
if you choose to enable it for your product or individual 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 all tool calls for usage-based billing and
|
|
||||||
analytics at a fine-grained level, so you can drill in and deeply
|
|
||||||
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.
|
|
||||||
Publishing deployments 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'>
|
|
||||||
That's just the start
|
|
||||||
</h4>
|
|
||||||
|
|
||||||
<p className='text-sm'>
|
|
||||||
<Link href={docsUrl} className='link'>
|
|
||||||
Check out our docs
|
|
||||||
</Link>{' '}
|
|
||||||
for more details on Agentic's MCP API gateway.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* Open source section */}
|
{/* Open source section */}
|
||||||
|
@ -214,7 +73,6 @@ export default function MCPAuthorsPage() {
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<p className=''>
|
<p className=''>
|
||||||
Open source is very dear to my heart, and I couldn't be happier that
|
|
||||||
Agentic is fully OSS. It's written in{' '}
|
Agentic is fully OSS. It's written in{' '}
|
||||||
<span className='font-semibold'>TypeScript</span> and has a small but
|
<span className='font-semibold'>TypeScript</span> and has a small but
|
||||||
vibrant developer community.{' '}
|
vibrant developer community.{' '}
|
||||||
|
@ -242,13 +100,15 @@ export default function MCPAuthorsPage() {
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* CTA section */}
|
{/* CTA section */}
|
||||||
<section className='flex flex-col gap-12 mb-16'>
|
<DotsSection className='mb-16'>
|
||||||
<h2 className='text-center text-balance leading-snug md:leading-none text-3xl font-heading'>
|
<div className='flex flex-col gap-12 z-10'>
|
||||||
Deploy Your MCP Today
|
<h2 className='text-center text-balance leading-snug md:leading-none text-3xl font-heading'>
|
||||||
</h2>
|
Deploy Your MCP Today
|
||||||
|
</h2>
|
||||||
|
|
||||||
<SupplySideCTA variant='github-2' />
|
<SupplySideCTA variant='github-2' />
|
||||||
</section>
|
</div>
|
||||||
|
</DotsSection>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,7 +105,6 @@ export default async function TheBestDamnLandingPageEver() {
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<p className=''>
|
<p className=''>
|
||||||
Open source is very dear to my heart, and I couldn't be happier that
|
|
||||||
Agentic is fully OSS. It's written in{' '}
|
Agentic is fully OSS. It's written in{' '}
|
||||||
<span className='font-semibold'>TypeScript</span> and has a small but
|
<span className='font-semibold'>TypeScript</span> and has a small but
|
||||||
vibrant developer community.{' '}
|
vibrant developer community.{' '}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { docsMarketplaceUrl } from '@/lib/config'
|
||||||
|
|
||||||
export function DemandSideCTA() {
|
export function DemandSideCTA() {
|
||||||
return (
|
return (
|
||||||
<div className='flex justify-center items-center gap-8'>
|
<div className='flex justify-center items-center gap-12'>
|
||||||
<HeroButton asChild className='h-full'>
|
<HeroButton asChild className='h-full'>
|
||||||
<Link href='/marketplace' className='font-mono'>
|
<Link href='/marketplace' className='font-mono'>
|
||||||
gotoTools();
|
gotoTools();
|
||||||
|
|
|
@ -0,0 +1,336 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import type { ComponentType, ReactNode } from 'react'
|
||||||
|
import {
|
||||||
|
ChartNoAxesCombinedIcon,
|
||||||
|
CheckCheckIcon,
|
||||||
|
CreditCardIcon,
|
||||||
|
DatabaseZapIcon,
|
||||||
|
HistoryIcon,
|
||||||
|
KeyRoundIcon,
|
||||||
|
ShieldCheckIcon,
|
||||||
|
TextSelectIcon,
|
||||||
|
UserIcon
|
||||||
|
} from 'lucide-react'
|
||||||
|
import {
|
||||||
|
motion,
|
||||||
|
type MotionValue,
|
||||||
|
useMotionTemplate,
|
||||||
|
useMotionValue
|
||||||
|
} from 'motion/react'
|
||||||
|
import Link from 'next/link'
|
||||||
|
|
||||||
|
import { calendarBookingUrl, docsUrl } from '@/lib/config'
|
||||||
|
|
||||||
|
import { GridPattern } from './grid-pattern'
|
||||||
|
|
||||||
|
type Feature = {
|
||||||
|
name: string
|
||||||
|
description: ReactNode
|
||||||
|
icon: ComponentType<{ className?: string }>
|
||||||
|
pattern: Omit<GridPattern, 'width' | 'height' | 'x'>
|
||||||
|
href?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const FEATURES: Feature[] = [
|
||||||
|
{
|
||||||
|
name: 'Auth',
|
||||||
|
description: (
|
||||||
|
<>
|
||||||
|
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>
|
||||||
|
.
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
icon: UserIcon,
|
||||||
|
pattern: {
|
||||||
|
y: 16,
|
||||||
|
squares: [
|
||||||
|
[0, 1],
|
||||||
|
[1, 3]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Stripe Billing',
|
||||||
|
description: (
|
||||||
|
<>
|
||||||
|
Charge for your MCP products with a flexible, declarative pricing model
|
||||||
|
built on top of Stripe. Agentic supports almost any combination of fixed
|
||||||
|
and <span className='font-semibold'>usage-based billing</span> models,
|
||||||
|
both at the MCP level, at the tool-call level, and at the custom metric
|
||||||
|
level (e.g., tokens, image transformations, etc).
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
icon: CreditCardIcon,
|
||||||
|
pattern: {
|
||||||
|
y: -6,
|
||||||
|
squares: [
|
||||||
|
[-1, 2],
|
||||||
|
[1, 3]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Support both MCP and HTTP',
|
||||||
|
description: (
|
||||||
|
<>
|
||||||
|
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 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.
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
icon: CheckCheckIcon,
|
||||||
|
pattern: {
|
||||||
|
y: 32,
|
||||||
|
squares: [
|
||||||
|
[0, 2],
|
||||||
|
[1, 4]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'API Keys',
|
||||||
|
description: (
|
||||||
|
<>
|
||||||
|
When a customer subscribes to your product, they're given a unique API
|
||||||
|
key. MCP URLs are appended with this API key to correlate usage with
|
||||||
|
their subscription. Customer HTTP tool calls use the same API key as a
|
||||||
|
standard HTTP <em>Authorization</em> header.
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
icon: KeyRoundIcon,
|
||||||
|
pattern: {
|
||||||
|
y: 22,
|
||||||
|
squares: [[0, 1]]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Rate-limiting',
|
||||||
|
description: (
|
||||||
|
<>
|
||||||
|
All agentic products are protected by durable rate-limiting built on top
|
||||||
|
of Cloudflare's global infrastructure. Customize the default
|
||||||
|
rate-limits, change them based on a customer's pricing plan, or create
|
||||||
|
custom tool-specific overrides. REST assured that your origin API will
|
||||||
|
be safe behind Agentic's API gateway.
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
icon: ShieldCheckIcon,
|
||||||
|
pattern: {
|
||||||
|
y: 2,
|
||||||
|
squares: [
|
||||||
|
[-2, 3],
|
||||||
|
[1, 4]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Caching',
|
||||||
|
description: (
|
||||||
|
<>
|
||||||
|
Opt-in to caching with familiar <em>cache-control</em> and{' '}
|
||||||
|
<em>stale-while-revalidate</em> options. MCP tool calls include caching
|
||||||
|
information in their <em>_meta</em> fields, providing parity with
|
||||||
|
standard HTTP headers. All caching takes place in Cloudflare's global
|
||||||
|
edge cache, and caching will only be enabled if you choose to enable it
|
||||||
|
for your product or individual tools.
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
icon: DatabaseZapIcon,
|
||||||
|
pattern: {
|
||||||
|
y: 8,
|
||||||
|
squares: [
|
||||||
|
[0, 2],
|
||||||
|
[-1, 1]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Analytics',
|
||||||
|
description: (
|
||||||
|
<>
|
||||||
|
Agentic tracks all tool calls for usage-based billing and analytics at a
|
||||||
|
fine-grained level, so you can drill in and deeply understand how your
|
||||||
|
customers are using your product.
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
icon: ChartNoAxesCombinedIcon,
|
||||||
|
pattern: {
|
||||||
|
y: -2,
|
||||||
|
squares: [[-2, 2]]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Versioning',
|
||||||
|
description: (
|
||||||
|
<>
|
||||||
|
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. Publishing
|
||||||
|
deployments publicly uses semantic versioning (<em>semver</em>), so your
|
||||||
|
customers can choose how to handle breaking changes.
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
icon: HistoryIcon,
|
||||||
|
pattern: {
|
||||||
|
y: 26,
|
||||||
|
squares: [
|
||||||
|
[2, 4],
|
||||||
|
[-2, 3]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "That's just the start",
|
||||||
|
description: (
|
||||||
|
<>Check out our docs for more details on Agentic's MCP gateway.</>
|
||||||
|
),
|
||||||
|
href: docsUrl,
|
||||||
|
icon: TextSelectIcon,
|
||||||
|
pattern: {
|
||||||
|
y: 13,
|
||||||
|
squares: [
|
||||||
|
[0, 2],
|
||||||
|
[0, 2]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
function Feature({ name, description, icon, pattern, href }: Feature) {
|
||||||
|
const mouseX = useMotionValue(0)
|
||||||
|
const mouseY = useMotionValue(0)
|
||||||
|
|
||||||
|
function onMouseMove({
|
||||||
|
currentTarget,
|
||||||
|
clientX,
|
||||||
|
clientY
|
||||||
|
}: React.MouseEvent<HTMLElement>) {
|
||||||
|
const { left, top } = currentTarget.getBoundingClientRect()
|
||||||
|
mouseX.set(clientX - left)
|
||||||
|
mouseY.set(clientY - top)
|
||||||
|
}
|
||||||
|
|
||||||
|
const content = (
|
||||||
|
<>
|
||||||
|
<FeaturePattern {...pattern} mouseX={mouseX} mouseY={mouseY} />
|
||||||
|
|
||||||
|
<div className='ring-gray-900/7.5 group-hover:ring-gray-900/10 absolute inset-0 rounded-2xl ring-1 ring-inset dark:ring-white/10 dark:group-hover:ring-white/20' />
|
||||||
|
|
||||||
|
<div className='relative rounded-2xl px-4 pb-4 pt-16'>
|
||||||
|
<FeatureIcon icon={icon} />
|
||||||
|
|
||||||
|
<h3 className='text-gray-900 mt-4 text-[0.875rem] font-semibold leading-7 dark:text-white'>
|
||||||
|
{/* <span className='absolute inset-0 rounded-2xl' /> */}
|
||||||
|
{name}
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<p className='text-gray-600 dark:text-gray-400 mt-1 text-[0.875rem] leading-[1.5rem]'>
|
||||||
|
{description}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
|
||||||
|
const className =
|
||||||
|
'dark:bg-white/2.5 bg-gray-50 hover:shadow-gray-900/5 group relative flex rounded-2xl transition-shadow hover:shadow-md dark:hover:shadow-black/5'
|
||||||
|
|
||||||
|
if (href) {
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
href={href}
|
||||||
|
key={name}
|
||||||
|
onMouseMove={onMouseMove}
|
||||||
|
className={className}
|
||||||
|
>
|
||||||
|
{content}
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<div key={name} onMouseMove={onMouseMove} className={className}>
|
||||||
|
{content}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
|
function FeatureIcon({ icon: Icon }: { icon: Feature['icon'] }) {
|
||||||
|
return (
|
||||||
|
<div className='dark:bg-white/7.5 bg-gray-900/5 ring-gray-900/25 group-hover:ring-gray-900/25 dark:group-hover:bg-sky-300/10 dark:group-hover:ring-sky-400 flex size-7 items-center justify-center rounded-full ring-1 backdrop-blur-[2px] transition duration-300 group-hover:bg-white/50 dark:ring-white/15'>
|
||||||
|
<Icon className='fill-gray-700/10 stroke-gray-700 group-hover:stroke-gray-900 dark:stroke-gray-400 dark:group-hover:stroke-sky-400 dark:group-hover:fill-sky-300/10 size-5 transition-colors duration-300 dark:fill-white/10' />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function FeaturePattern({
|
||||||
|
mouseX,
|
||||||
|
mouseY,
|
||||||
|
...gridProps
|
||||||
|
}: Feature['pattern'] & {
|
||||||
|
mouseX: MotionValue<number>
|
||||||
|
mouseY: MotionValue<number>
|
||||||
|
}) {
|
||||||
|
const maskImage = useMotionTemplate`radial-gradient(180px at ${mouseX}px ${mouseY}px, white, transparent)`
|
||||||
|
const style = { maskImage, WebkitMaskImage: maskImage }
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='pointer-events-none'>
|
||||||
|
<div className='absolute inset-0 rounded-2xl transition duration-300 [mask-image:linear-gradient(white,transparent)] group-hover:opacity-50'>
|
||||||
|
<GridPattern
|
||||||
|
width={72}
|
||||||
|
height={56}
|
||||||
|
x='50%'
|
||||||
|
className='dark:fill-white/1 dark:stroke-white/2.5 absolute inset-x-0 inset-y-[-30%] h-[160%] w-full skew-y-[-18deg] fill-black/[0.02] stroke-black/5'
|
||||||
|
{...gridProps}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<motion.div
|
||||||
|
className='from-sky-100 to-sky-300 dark:from-sky-500 dark:to-sky-300 absolute inset-0 rounded-2xl bg-gradient-to-r opacity-0 transition duration-300 group-hover:opacity-50 dark:group-hover:opacity-15'
|
||||||
|
style={style}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<motion.div
|
||||||
|
className='absolute inset-0 rounded-2xl opacity-0 mix-blend-overlay transition duration-300 group-hover:opacity-100'
|
||||||
|
style={style}
|
||||||
|
>
|
||||||
|
<GridPattern
|
||||||
|
width={72}
|
||||||
|
height={56}
|
||||||
|
x='50%'
|
||||||
|
className='dark:fill-white/2.5 absolute inset-x-0 inset-y-[-30%] h-[160%] w-full skew-y-[-18deg] fill-black/50 stroke-black/70 dark:stroke-white/10'
|
||||||
|
{...gridProps}
|
||||||
|
/>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Features() {
|
||||||
|
return (
|
||||||
|
<div className='xl:max-w-none'>
|
||||||
|
<div className='not-prose grid grid-cols-1 gap-8 sm:grid-cols-2 xl:grid-cols-3'>
|
||||||
|
{FEATURES.map((feature) => (
|
||||||
|
<Feature key={feature.name} {...feature} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
|
@ -3,7 +3,7 @@ import Link from 'next/link'
|
||||||
import { ActiveLink } from '@/components/active-link'
|
import { ActiveLink } from '@/components/active-link'
|
||||||
import { GitHubIcon } from '@/icons/github'
|
import { GitHubIcon } from '@/icons/github'
|
||||||
import { TwitterIcon } from '@/icons/twitter'
|
import { TwitterIcon } from '@/icons/twitter'
|
||||||
import { copyright, githubUrl, twitterUrl } from '@/lib/config'
|
import { copyright, docsUrl, githubUrl, twitterUrl } from '@/lib/config'
|
||||||
|
|
||||||
export function Footer() {
|
export function Footer() {
|
||||||
return (
|
return (
|
||||||
|
@ -21,12 +21,24 @@ export function Footer() {
|
||||||
</ActiveLink>
|
</ActiveLink>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
<span>
|
||||||
|
<ActiveLink href='/marketplace' className='link'>
|
||||||
|
MCP Marketplace
|
||||||
|
</ActiveLink>
|
||||||
|
</span>
|
||||||
|
|
||||||
<span>
|
<span>
|
||||||
<ActiveLink href='/mcp-authors' className='link'>
|
<ActiveLink href='/mcp-authors' className='link'>
|
||||||
For MCP Authors
|
For MCP Authors
|
||||||
</ActiveLink>
|
</ActiveLink>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
<span>
|
||||||
|
<ActiveLink href={docsUrl} className='link'>
|
||||||
|
Docs
|
||||||
|
</ActiveLink>
|
||||||
|
</span>
|
||||||
|
|
||||||
<span>
|
<span>
|
||||||
<ActiveLink href='/about' className='link'>
|
<ActiveLink href='/about' className='link'>
|
||||||
About
|
About
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
import { type SVGProps, useId } from 'react'
|
||||||
|
|
||||||
|
export type GridPattern = Omit<
|
||||||
|
SVGProps<SVGSVGElement>,
|
||||||
|
'width' | 'height' | 'x' | 'y'
|
||||||
|
> & {
|
||||||
|
width: number
|
||||||
|
height: number
|
||||||
|
x: string | number
|
||||||
|
y: string | number
|
||||||
|
squares: Array<[x: number, y: number]>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function GridPattern({
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
squares,
|
||||||
|
...props
|
||||||
|
}: GridPattern) {
|
||||||
|
const patternId = useId()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<svg aria-hidden='true' {...props}>
|
||||||
|
<defs>
|
||||||
|
<pattern
|
||||||
|
id={patternId}
|
||||||
|
width={width}
|
||||||
|
height={height}
|
||||||
|
patternUnits='userSpaceOnUse'
|
||||||
|
x={x}
|
||||||
|
y={y}
|
||||||
|
>
|
||||||
|
<path d={`M.5 ${height}V.5H${width}`} fill='none' />
|
||||||
|
</pattern>
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
<rect
|
||||||
|
width='100%'
|
||||||
|
height='100%'
|
||||||
|
strokeWidth={0}
|
||||||
|
fill={`url(#${patternId})`}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{squares && (
|
||||||
|
<svg x={x} y={y} className='overflow-visible'>
|
||||||
|
<title>square</title>
|
||||||
|
|
||||||
|
{squares.map(([x, y]) => (
|
||||||
|
<rect
|
||||||
|
strokeWidth='0'
|
||||||
|
key={`${x}-${y}`}
|
||||||
|
width={width + 1}
|
||||||
|
height={height + 1}
|
||||||
|
x={x * width}
|
||||||
|
y={y * height}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</svg>
|
||||||
|
)}
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
|
@ -19,7 +19,7 @@ export function Header() {
|
||||||
|
|
||||||
<div className='flex justify-end items-center h-full gap-4'>
|
<div className='flex justify-end items-center h-full gap-4'>
|
||||||
<ActiveLink href='/marketplace' className='link'>
|
<ActiveLink href='/marketplace' className='link'>
|
||||||
Marketplace
|
MCP Marketplace
|
||||||
</ActiveLink>
|
</ActiveLink>
|
||||||
|
|
||||||
<ActiveLink href={docsUrl} className='link'>
|
<ActiveLink href={docsUrl} className='link'>
|
||||||
|
|
|
@ -19,7 +19,7 @@ export function SupplySideCTA({
|
||||||
const ctx = useAgentic()
|
const ctx = useAgentic()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex justify-center items-center gap-8'>
|
<div className='flex justify-center items-center gap-12'>
|
||||||
<HeroButton asChild className=''>
|
<HeroButton asChild className=''>
|
||||||
<Link
|
<Link
|
||||||
href={
|
href={
|
||||||
|
|
Ładowanie…
Reference in New Issue