diff --git a/apps/blog/components.json b/apps/blog/components.json index efa8bd9fad..87bf1a15c6 100644 --- a/apps/blog/components.json +++ b/apps/blog/components.json @@ -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": "" diff --git a/apps/docs/components.json b/apps/docs/components.json index efa8bd9fad..87bf1a15c6 100644 --- a/apps/docs/components.json +++ b/apps/docs/components.json @@ -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": "" diff --git a/apps/eclipse/components.json b/apps/eclipse/components.json index 27a7524b70..d8aed6a2e1 100644 --- a/apps/eclipse/components.json +++ b/apps/eclipse/components.json @@ -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": "" diff --git a/apps/site/components.json b/apps/site/components.json index efa8bd9fad..87bf1a15c6 100644 --- a/apps/site/components.json +++ b/apps/site/components.json @@ -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": "" diff --git a/apps/site/src/app/mcp/_components/agent-card.tsx b/apps/site/src/app/mcp/_components/agent-card.tsx new file mode 100644 index 0000000000..d052cb2132 --- /dev/null +++ b/apps/site/src/app/mcp/_components/agent-card.tsx @@ -0,0 +1,42 @@ +import Image from "next/image"; +import type { LucideIcon } from "lucide-react"; + +export function AgentCard({ + logo, + alt, + icon: Icon, + href, +}: { + logo: string | null; + alt: string; + icon: LucideIcon; + href: string; +}) { + return ( + + {logo ? ( + + ) : ( + Any AI agent + )} + + + + + ); +} diff --git a/apps/site/src/app/mcp/_components/capability-cards.tsx b/apps/site/src/app/mcp/_components/capability-cards.tsx new file mode 100644 index 0000000000..41e41f5ba8 --- /dev/null +++ b/apps/site/src/app/mcp/_components/capability-cards.tsx @@ -0,0 +1,87 @@ +import type { LucideIcon } from "lucide-react"; + +import { McpBubble } from "./mcp-bubble"; + +const capabilityIconClass = "size-6 text-foreground-ppg shrink-0"; + +export function MobileCapabilityCard({ + icon: Icon, + title, + description, + prompt, + mobileTall, +}: { + icon: LucideIcon; + title: string; + description: string; + prompt: string; + mobileTall: boolean; +}) { + return ( +
+
+
+
+ +
+

+ {title} +

+
+

+ {description} +

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

+ {title} +

+
+

+ {description} +

+
+
+ {prompt} +
+
+ ); +} diff --git a/apps/site/src/app/mcp/_components/index.ts b/apps/site/src/app/mcp/_components/index.ts new file mode 100644 index 0000000000..2a794b53ad --- /dev/null +++ b/apps/site/src/app/mcp/_components/index.ts @@ -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"; diff --git a/apps/site/src/app/mcp/_components/mcp-agents-section.tsx b/apps/site/src/app/mcp/_components/mcp-agents-section.tsx new file mode 100644 index 0000000000..737c76927b --- /dev/null +++ b/apps/site/src/app/mcp/_components/mcp-agents-section.tsx @@ -0,0 +1,49 @@ +import { Button } from "@prisma/eclipse"; +import type { LucideIcon } from "lucide-react"; + +import { AgentCard } from "./agent-card"; + +export type McpAgent = { + logo: string | null; + alt: string; + icon: LucideIcon; + href: string; +}; + +export function McpAgentsSection({ + docsHref, + agents, +}: { + docsHref: string; + agents: readonly McpAgent[]; +}) { + return ( +
+
+
+

+ Works with your AI agent +

+

+ Works with any AI agent, whether you prefer to use a remote or a local server, + we've got you. +

+
+ +
+ {agents.map(({ logo, alt, icon, href }) => ( + + ))} +
+ + +
+
+ ); +} diff --git a/apps/site/src/app/mcp/_components/mcp-bubble.tsx b/apps/site/src/app/mcp/_components/mcp-bubble.tsx new file mode 100644 index 0000000000..2cf2b7fb52 --- /dev/null +++ b/apps/site/src/app/mcp/_components/mcp-bubble.tsx @@ -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 = { + "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 ?
{children}
: children; + + return ( +
+
+ {body} +
+
+ ); +} diff --git a/apps/site/src/app/mcp/_components/mcp-capabilities-section.tsx b/apps/site/src/app/mcp/_components/mcp-capabilities-section.tsx new file mode 100644 index 0000000000..002e1fdbf7 --- /dev/null +++ b/apps/site/src/app/mcp/_components/mcp-capabilities-section.tsx @@ -0,0 +1,59 @@ +import type { LucideIcon } from "lucide-react"; + +import { CapabilityCard, MobileCapabilityCard } from "./capability-cards"; + +export type McpCapability = { + icon: LucideIcon; + title: string; + description: string; + prompt: string; + mobileTall: boolean; +}; + +export function McpCapabilitiesSection({ + capabilities, +}: { + capabilities: readonly McpCapability[]; +}) { + return ( +
+
+
+

+ What can I do with MCP? +

+
+
+ Use Prisma Postgres +
+
+ Own database +
+
+
+ {capabilities.map((cap) => ( + + ))} +
+
+ +
+

+ What can I do with MCP? +

+ +
+ {capabilities.slice(0, 2).map(({ mobileTall: _t, ...cap }) => ( + + ))} +
+
+ {capabilities.slice(2).map(({ mobileTall: _t, ...cap }) => ( + + ))} +
+
+
+
+ ); +} diff --git a/apps/site/src/app/mcp/_components/mcp-cta-section.tsx b/apps/site/src/app/mcp/_components/mcp-cta-section.tsx new file mode 100644 index 0000000000..1ca59f1bfd --- /dev/null +++ b/apps/site/src/app/mcp/_components/mcp-cta-section.tsx @@ -0,0 +1,68 @@ +import { buttonVariants } from "@prisma/eclipse"; +import { ArrowRight, BookOpen } from "lucide-react"; + +export function McpCtaSection({ docsHref }: { docsHref: string }) { + return ( +
+
+
+
+
+

+ Start Building with AI +

+

+ Join thousands of developers, and agents, already using Prisma MCP for faster, more + intuitive database workflows. +

+
+ +
+ + +

+ 2-minute setup • Works with all MCP tools +

+
+
+
+
+ ); +} diff --git a/apps/site/src/app/mcp/_components/mcp-hero-section.tsx b/apps/site/src/app/mcp/_components/mcp-hero-section.tsx new file mode 100644 index 0000000000..2dc06204a2 --- /dev/null +++ b/apps/site/src/app/mcp/_components/mcp-hero-section.tsx @@ -0,0 +1,127 @@ +import { Button } from "@prisma/eclipse"; +import type { LucideIcon } from "lucide-react"; +import { ArrowRight, MessageSquareCode } from "lucide-react"; + +import { McpBubble } from "./mcp-bubble"; + +export type McpHeroFeature = { + icon: LucideIcon; + line1: string; + line2: string; + mobileText?: string; +}; + +const heroFeatureIconClass = "size-6 text-foreground-ppg shrink-0"; + +export function McpHeroSection({ + docsHref, + features, +}: { + docsHref: string; + features: readonly McpHeroFeature[]; +}) { + return ( +
+
+
+

+ + Prisma MCP Server +

+ +

+ Your Database Workflow, +
+ Powered by AI + _ +

+
+ +

+ Manage your databases with natural language via MCP using your AI tool of choice. + Works great with Prisma Postgres_ +

+
+
+ + + +
+ {features.map((feature) => { + const FeatureIcon = feature.icon; + return ( +
+
+ +
+

+ {feature.mobileText ?? `${feature.line1} ${feature.line2}`} +

+
+ ); + })} +
+
+ +
+
+
+

+ + Prisma MCP Server +

+
+
+ +

+ Your Database Workflow, Powered by AI + _ +

+
+
+
+ +

+ Manage your databases with natural language via MCP in Claude, Codex, Cursor, + Warp, ChatGPT, and other AI agents. Works great with Prisma Postgres_ +

+
+
+
+
+ + +
+ +
+ {features.map(({ icon: FeatureIcon, line1, line2 }) => ( +
+
+ +
+

+ {line1} +
+ {line2} +

+
+ ))} +
+
+
+ ); +} diff --git a/apps/site/src/app/mcp/_components/mcp-video-section.tsx b/apps/site/src/app/mcp/_components/mcp-video-section.tsx new file mode 100644 index 0000000000..66cac6368c --- /dev/null +++ b/apps/site/src/app/mcp/_components/mcp-video-section.tsx @@ -0,0 +1,18 @@ +export function McpVideoSection() { + return ( +
+
+
+