Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/blog/components.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"tsx": true,
"tailwind": {
"config": "",
"css": "src/app/global.css",
"css": "../../packages/ui/src/styles/globals.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/components.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"tsx": true,
"tailwind": {
"config": "",
"css": "src/app/global.css",
"css": "../../packages/ui/src/styles/globals.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
Expand Down
4 changes: 2 additions & 2 deletions apps/eclipse/components.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
"rsc": true,
"tsx": true,
"tailwind": {
"config": "tailwind.config.ts",
"css": "src/styles/globals.css",
"config": "",
"css": "src/app/global.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
Expand Down
2 changes: 1 addition & 1 deletion apps/site/components.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"tsx": true,
"tailwind": {
"config": "",
"css": "src/app/global.css",
"css": "../../packages/ui/src/styles/globals.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
Expand Down
41 changes: 41 additions & 0 deletions apps/site/src/app/mcp/_components/agent-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import Image from "next/image";

export function AgentCard({
logo,
alt,
icon,
href,
}: {
logo: string | null;
alt: string;
icon: string;
href: string;
}) {
return (
<a
href={href}
title={alt}
aria-label={alt}
className="group relative flex h-[120px] w-full items-center justify-center rounded-[12px] border border-stroke-neutral bg-background-neutral-weaker no-underline outline-offset-4 transition-[border-color,background-color] hover:border-stroke-ppg/60 hover:bg-background-neutral focus-visible:ring-2 focus-visible:ring-stroke-ppg"
>
{logo ? (
<Image
src={logo}
alt=""
width={48}
height={48}
className="size-12 object-contain opacity-55 grayscale transition-opacity group-hover:opacity-80 dark:brightness-0 dark:invert"
unoptimized
/>
) : (
<span className="font-mono text-lg text-foreground-neutral-weak">Any AI agent</span>
)}
<span
className="absolute right-[7px] top-[7px] text-sm text-foreground-neutral-weaker opacity-60 transition-opacity group-hover:opacity-100"
aria-hidden
>
<i className={icon} />
</span>
</a>
);
}
83 changes: 83 additions & 0 deletions apps/site/src/app/mcp/_components/capability-cards.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { McpBubble } from "./mcp-bubble";

export function MobileCapabilityCard({
icon,
title,
description,
prompt,
mobileTall,
}: {
icon: string;
title: string;
description: string;
prompt: string;
mobileTall: boolean;
}) {
return (
<div
className={`flex w-full flex-col overflow-hidden rounded-[12px] border border-stroke-neutral/40 bg-background-default shadow-[0_1px_2px_rgba(0,0,0,0.04)] dark:border-white/8 dark:bg-[radial-gradient(circle_at_top_left,rgba(10,112,100,0.10),transparent_28%),linear-gradient(180deg,#08111c_0%,#060d18_100%)] ${
mobileTall ? "min-h-[227px]" : "min-h-[203px]"
}`}
>
<div className="flex flex-col gap-4 p-4">
<div className="flex items-center gap-4">
<div className="flex size-12 shrink-0 items-center justify-center rounded-[6px] bg-background-ppg">
<i className={`${icon} text-2xl text-foreground-ppg`} aria-hidden />
</div>
<h4 className="font-sans-display text-[20px] leading-7 font-extrabold text-foreground-neutral">
{title}
</h4>
</div>
<p className="max-w-full text-[16px] leading-6 text-foreground-neutral-weak">
{description}
</p>
</div>
<div className="mt-auto px-3.5 pb-3.5">
<McpBubble variant={mobileTall ? "prompt-mobile-tall" : "prompt-mobile"}>
{prompt}
</McpBubble>
</div>
</div>
);
}

export function CapabilityCard({
icon,
title,
description,
prompt,
size,
}: {
icon: string;
title: string;
description: string;
prompt: string;
size: "wide" | "compact";
}) {
const isWide = size === "wide";

return (
<div
className={`flex w-full flex-col overflow-hidden rounded-[12px] border border-stroke-neutral/40 bg-background-default shadow-[0_1px_2px_rgba(0,0,0,0.04)] dark:border-white/8 dark:bg-[radial-gradient(circle_at_top_left,rgba(10,112,100,0.10),transparent_28%),linear-gradient(180deg,#08111c_0%,#060d18_100%)] ${
isWide ? "md:min-h-[179px] md:w-[590px]" : "md:min-h-[203px] md:w-[389px]"
}`}
>
<div className="flex flex-col gap-4 p-4">
<div className="flex items-center gap-4">
<div className="flex size-12 shrink-0 items-center justify-center rounded-[6px] bg-background-ppg">
<i className={`${icon} text-2xl text-foreground-ppg`} aria-hidden />
</div>
<h4 className="font-sans-display text-[20px] leading-7 font-extrabold text-foreground-neutral">
{title}
</h4>
</div>
<p className="max-w-full text-[16px] leading-6 text-foreground-neutral-weak">
{description}
</p>
</div>
<div className="mt-auto px-4 pb-4">
<McpBubble variant={isWide ? "prompt-wide" : "prompt-compact"}>{prompt}</McpBubble>
</div>
</div>
);
}
12 changes: 12 additions & 0 deletions apps/site/src/app/mcp/_components/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export { AgentCard } from "./agent-card";
export { CapabilityCard, MobileCapabilityCard } from "./capability-cards";
export type { McpAgent } from "./mcp-agents-section";
export { McpAgentsSection } from "./mcp-agents-section";
export type { McpBubbleVariant } from "./mcp-bubble";
export { McpBubble } from "./mcp-bubble";
export type { McpCapability } from "./mcp-capabilities-section";
export { McpCapabilitiesSection } from "./mcp-capabilities-section";
export { McpCtaSection } from "./mcp-cta-section";
export type { McpHeroFeature } from "./mcp-hero-section";
export { McpHeroSection } from "./mcp-hero-section";
export { McpVideoSection } from "./mcp-video-section";
48 changes: 48 additions & 0 deletions apps/site/src/app/mcp/_components/mcp-agents-section.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Button } from "@prisma/eclipse";

import { AgentCard } from "./agent-card";

export type McpAgent = {
logo: string | null;
alt: string;
icon: string;
href: string;
};

export function McpAgentsSection({
docsHref,
agents,
}: {
docsHref: string;
agents: readonly McpAgent[];
}) {
return (
<section className="px-4 py-12 md:px-0">
<div className="mx-auto flex max-w-[790px] flex-col items-center gap-12 text-center">
<div className="flex max-w-[768px] flex-col items-center gap-4">
<h2 className="font-sans-display text-4xl font-black text-foreground-neutral md:text-5xl">
Works with your AI agent
</h2>
<p className="text-base leading-6 text-foreground-neutral-weak">
Works with any AI agent, whether you prefer to use a remote or a local server,
we&apos;ve got you.
</p>
</div>

<div className="grid w-full max-w-[368px] grid-cols-2 gap-4 md:max-w-[790px] md:grid-cols-4 md:gap-8">
{agents.map(({ logo, alt, icon, href }) => (
<AgentCard key={alt} logo={logo} alt={alt} icon={icon} href={href} />
))}
</div>

<Button
href={docsHref}
variant={"link"}
className="text-sm font-semibold text-foreground-ppg underline"
>
Want to see your tool listed?
</Button>
</div>
</section>
);
}
94 changes: 94 additions & 0 deletions apps/site/src/app/mcp/_components/mcp-bubble.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import type { ReactNode } from "react";

const fillTitle = "#030712";
const fillTeal = "#042F2E";

export type McpBubbleVariant =
| "hero-desktop-title"
| "hero-desktop-description"
| "hero-mobile-title"
| "hero-mobile-description"
| "prompt-mobile"
| "prompt-mobile-tall"
| "prompt-wide"
| "prompt-compact";

type BubbleConfig = {
shell: string;
fill: string;
monoPrompt: boolean;
};

const config: Record<McpBubbleVariant, BubbleConfig> = {
"hero-desktop-title": {
fill: fillTitle,
monoPrompt: false,
shell:
"min-h-[67px] items-center justify-center rounded-xl border border-stroke-ppg px-6 py-3 md:min-h-[67px] md:px-8",
},
"hero-desktop-description": {
fill: fillTeal,
monoPrompt: false,
shell:
"min-h-[72px] items-center rounded-xl border border-stroke-ppg px-6 py-3 md:min-h-[72px] md:px-6",
},
"hero-mobile-title": {
fill: fillTitle,
monoPrompt: false,
shell:
"min-h-[120px] items-center justify-center rounded-xl border border-stroke-ppg px-6 py-6 sm:min-h-[128px]",
},
"hero-mobile-description": {
fill: fillTeal,
monoPrompt: false,
shell:
"min-h-[108px] items-center rounded-xl border border-stroke-ppg px-4 py-5 sm:min-h-[112px]",
},
"prompt-mobile": {
fill: fillTeal,
monoPrompt: true,
shell:
"items-center rounded-[10px] border border-stroke-ppg px-3.5 py-2 shadow-none sm:px-4 min-h-[48px]",
},
"prompt-mobile-tall": {
fill: fillTeal,
monoPrompt: true,
shell:
"items-center rounded-[10px] border border-stroke-ppg px-3.5 py-2.5 shadow-none sm:px-4 min-h-[64px] sm:min-h-[72px]",
},
"prompt-wide": {
fill: fillTeal,
monoPrompt: true,
shell:
"items-center rounded-[10px] border border-stroke-ppg px-3.5 py-2 shadow-none sm:px-4 min-h-[41px] py-2 md:min-h-[45px]",
},
"prompt-compact": {
fill: fillTeal,
monoPrompt: true,
shell:
"items-center rounded-[10px] border border-stroke-ppg px-3.5 py-2 shadow-none sm:px-4 min-h-[44px] py-2 md:min-h-[50px]",
},
};

const monoPromptClass =
"w-full font-mono text-[13px] leading-snug text-foreground-ppg-reverse-weak sm:text-sm sm:leading-5";

export function McpBubble({
variant,
children,
}: {
variant: McpBubbleVariant;
children: ReactNode;
}) {
const { shell, fill, monoPrompt } = config[variant];

const body = monoPrompt ? <div className={monoPromptClass}>{children}</div> : children;

return (
<div className="relative w-full">
<div className={`relative z-1 flex w-full ${shell}`} style={{ backgroundColor: fill }}>
{body}
</div>
</div>
);
}
57 changes: 57 additions & 0 deletions apps/site/src/app/mcp/_components/mcp-capabilities-section.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { CapabilityCard, MobileCapabilityCard } from "./capability-cards";

export type McpCapability = {
icon: string;
title: string;
description: string;
prompt: string;
mobileTall: boolean;
};

export function McpCapabilitiesSection({
capabilities,
}: {
capabilities: readonly McpCapability[];
}) {
return (
<section className="py-element-4xl">
<div className="mx-auto max-w-[1200px] px-4 py-12 md:px-0">
<div className="md:hidden">
<h2 className="text-center font-sans-display text-4xl font-black tracking-tight text-foreground-neutral">
What can I do with MCP?
</h2>
<div className="mx-auto mt-8 flex w-full max-w-[368px] items-center rounded-full border border-stroke-neutral bg-background-neutral-weaker p-1">
<div className="flex h-10 shrink-0 items-center rounded-full bg-background-ppg-reverse px-4 font-sans-display text-base font-bold text-foreground-ppg-reverse">
Use Prisma Postgres
</div>
<div className="flex min-w-0 flex-1 items-center justify-center px-3 font-sans-display text-base font-bold text-foreground-neutral">
Own database
</div>
</div>
<div className="mx-auto mt-8 flex max-w-[368px] flex-col gap-4">
{capabilities.map((cap) => (
<MobileCapabilityCard key={cap.title} {...cap} />
))}
</div>
</div>

<div className="hidden md:block">
<h2 className="text-center font-sans-display text-4xl font-black tracking-tight text-foreground-neutral md:text-5xl">
What can I do with MCP?
</h2>

<div className="mt-12 flex flex-col gap-4 md:flex-row md:gap-5">
{capabilities.slice(0, 2).map(({ mobileTall: _t, ...cap }) => (
<CapabilityCard key={cap.title} size="wide" {...cap} />
))}
</div>
<div className="mt-4 flex flex-col gap-4 md:flex-row md:justify-between">
{capabilities.slice(2).map(({ mobileTall: _t, ...cap }) => (
<CapabilityCard key={cap.title} size="compact" {...cap} />
))}
</div>
</div>
</div>
</section>
);
}
Loading
Loading