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/public/mcp/logos/chatgpt.svg b/apps/site/public/mcp/logos/chatgpt.svg
new file mode 100644
index 0000000000..685806303d
--- /dev/null
+++ b/apps/site/public/mcp/logos/chatgpt.svg
@@ -0,0 +1,3 @@
+
diff --git a/apps/site/public/mcp/logos/claude-code.svg b/apps/site/public/mcp/logos/claude-code.svg
new file mode 100644
index 0000000000..7ef4d2d53e
--- /dev/null
+++ b/apps/site/public/mcp/logos/claude-code.svg
@@ -0,0 +1,3 @@
+
diff --git a/apps/site/public/mcp/logos/cursor.svg b/apps/site/public/mcp/logos/cursor.svg
new file mode 100644
index 0000000000..cf81f414a1
--- /dev/null
+++ b/apps/site/public/mcp/logos/cursor.svg
@@ -0,0 +1,21 @@
+
diff --git a/apps/site/public/mcp/logos/gemini.svg b/apps/site/public/mcp/logos/gemini.svg
new file mode 100644
index 0000000000..4d56d9f36e
--- /dev/null
+++ b/apps/site/public/mcp/logos/gemini.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/apps/site/public/mcp/logos/vscode.svg b/apps/site/public/mcp/logos/vscode.svg
new file mode 100644
index 0000000000..d57cde7346
--- /dev/null
+++ b/apps/site/public/mcp/logos/vscode.svg
@@ -0,0 +1,12 @@
+
diff --git a/apps/site/public/mcp/logos/warp.svg b/apps/site/public/mcp/logos/warp.svg
new file mode 100644
index 0000000000..64f4ae5969
--- /dev/null
+++ b/apps/site/public/mcp/logos/warp.svg
@@ -0,0 +1,11 @@
+
diff --git a/apps/site/public/mcp/logos/windsurf.svg b/apps/site/public/mcp/logos/windsurf.svg
new file mode 100644
index 0000000000..4ec64a8a5b
--- /dev/null
+++ b/apps/site/public/mcp/logos/windsurf.svg
@@ -0,0 +1,3 @@
+
diff --git a/apps/site/src/app/global.css b/apps/site/src/app/global.css
index f0100f4a23..bb9ed50fc5 100644
--- a/apps/site/src/app/global.css
+++ b/apps/site/src/app/global.css
@@ -45,6 +45,21 @@
)
}
+@keyframes mcp-cursor-blink {
+ 0%,
+ 48% {
+ opacity: 1;
+ }
+ 52%,
+ 100% {
+ opacity: 0;
+ }
+}
+
+.mcp-type-cursor {
+ animation: mcp-cursor-blink 1s step-end infinite;
+}
+
@keyframes glitch-1 {
0% {
clip-path: inset(20% 0 60% 0);
@@ -86,4 +101,3 @@
clip-path: inset(75% 0 15% 0);
}
}
-
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..376a228fed
--- /dev/null
+++ b/apps/site/src/app/mcp/_components/agent-card.tsx
@@ -0,0 +1,45 @@
+import Image from "next/image";
+
+export function AgentCard({
+ logo,
+ alt,
+ icon,
+ href,
+}: {
+ logo: string | null;
+ alt: string;
+ icon: string | null;
+ href: string;
+}) {
+ return (
+
+ {logo ? (
+
+ ) : (
+
+ Any AI agent
+
+ )}
+ {icon ? (
+
+
+
+ ) : null}
+
+ );
+}
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..74fd963190
--- /dev/null
+++ b/apps/site/src/app/mcp/_components/capability-cards.tsx
@@ -0,0 +1,112 @@
+import { McpPromptBubble } from "./mcp-bubble";
+
+const capabilityIconClass = "shrink-0 text-[24px] text-foreground-ppg";
+const capabilityCardClass =
+ "relative flex w-full flex-col overflow-hidden rounded-[12px] border border-stroke-neutral bg-[linear-gradient(180deg,var(--color-background-default)_0%,var(--color-background-ppg)_262.5%)] shadow-box-low";
+const capabilityHeaderClass = "flex items-center gap-4";
+const capabilityDescriptionClass =
+ "max-w-full text-[16px] leading-6 text-foreground-neutral-weak";
+
+function CapabilityCardContent({
+ icon,
+ title,
+ description,
+}: {
+ icon: string;
+ title: string;
+ description: string;
+}) {
+ return (
+
+ );
+}
+
+export function MobileCapabilityCard({
+ icon,
+ title,
+ description,
+ prompt,
+ mobileTall,
+}: {
+ icon: string;
+ title: string;
+ description: string;
+ prompt: string;
+ mobileTall: boolean;
+}) {
+ return (
+
+ );
+}
+
+export function CapabilityCard({
+ icon,
+ title,
+ description,
+ prompt,
+ mobileTall = false,
+ size,
+}: {
+ icon: string;
+ title: string;
+ description: string;
+ prompt: string;
+ mobileTall?: boolean;
+ size: "wide" | "compact";
+}) {
+ const isWide = size === "wide";
+ const cardHeightClass = mobileTall
+ ? "h-[227px] xl:h-[179px]"
+ : isWide
+ ? "h-[203px] xl:h-[179px]"
+ : "h-[203px]";
+ const promptInsetClass = isWide
+ ? "bottom-[14px] left-[14px] right-[14px] xl:bottom-[15px] xl:left-[16px] xl:right-[25px]"
+ : "bottom-[14px] left-[14px] right-[14px] xl:left-[16px] xl:right-[27px]";
+ const contentPadClass = mobileTall
+ ? "pb-[104px] xl:pb-[60px]"
+ : isWide
+ ? "pb-[80px] xl:pb-[60px]"
+ : "pb-[80px] xl:pb-[66px]";
+ const promptVariant = mobileTall
+ ? "mobile-tall"
+ : isWide
+ ? "wide"
+ : "compact";
+
+ return (
+
+ );
+}
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..9cff01c390
--- /dev/null
+++ b/apps/site/src/app/mcp/_components/mcp-agents-section.tsx
@@ -0,0 +1,48 @@
+import { Button } from "@prisma/eclipse";
+
+import { AgentCard } from "./agent-card";
+
+export type McpAgent = {
+ logo: string | null;
+ alt: string;
+ icon: string | null;
+ 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..b95d1770f9
--- /dev/null
+++ b/apps/site/src/app/mcp/_components/mcp-bubble.tsx
@@ -0,0 +1,124 @@
+import { useId, type ReactNode } from "react";
+
+const bubbleShadow = "shadow-box-low dark:shadow-box-high";
+
+export type McpBubbleVariant =
+ | "hero-desktop-title"
+ | "hero-desktop-description"
+ | "hero-mobile-title"
+ | "hero-mobile-description";
+
+export type McpPromptBubbleVariant =
+ | "mobile"
+ | "mobile-tall"
+ | "wide"
+ | "compact";
+
+type BubbleConfig = {
+ shell: string;
+ tailSide: "left" | "right";
+};
+
+const config: Record = {
+ "hero-desktop-title": {
+ tailSide: "right",
+ shell: `min-h-[120px] items-center justify-center rounded-xl px-5 py-5 sm:min-h-[96px] sm:px-6 sm:py-4 lg:min-h-[72px] lg:px-6 ${bubbleShadow} [--mcp-bubble-fill:var(--color-background-default)] dark:[--mcp-bubble-fill:var(--color-background-neutral-weaker)] [--mcp-bubble-stroke:var(--color-stroke-ppg)] [background-color:var(--mcp-bubble-fill)] [border-color:var(--mcp-bubble-stroke)]`,
+ },
+ "hero-desktop-description": {
+ tailSide: "left",
+ shell: `min-h-[108px] items-center rounded-xl px-4 py-4 sm:min-h-[92px] sm:px-5 sm:py-3.5 lg:min-h-[78px] lg:px-6 lg:py-3 ${bubbleShadow} [--mcp-bubble-fill:var(--color-background-ppg)] [--mcp-bubble-stroke:var(--color-stroke-ppg)] [background-color:var(--mcp-bubble-fill)] [border-color:var(--mcp-bubble-stroke)]`,
+ },
+ "hero-mobile-title": {
+ tailSide: "right",
+ shell: `min-h-[120px] items-center justify-center rounded-xl px-5 py-5 sm:min-h-[128px] sm:px-6 ${bubbleShadow} [--mcp-bubble-fill:var(--color-background-default)] dark:[--mcp-bubble-fill:var(--color-background-neutral-weaker)] [--mcp-bubble-stroke:var(--color-stroke-ppg)] [background-color:var(--mcp-bubble-fill)] [border-color:var(--mcp-bubble-stroke)]`,
+ },
+ "hero-mobile-description": {
+ tailSide: "left",
+ shell: `min-h-[108px] items-center rounded-xl px-4 py-4 sm:min-h-[112px] sm:px-5 ${bubbleShadow} [--mcp-bubble-fill:var(--color-background-ppg)] [--mcp-bubble-stroke:var(--color-stroke-ppg)] [background-color:var(--mcp-bubble-fill)] [border-color:var(--mcp-bubble-stroke)]`,
+ },
+};
+
+const promptConfig: Record = {
+ mobile: "min-h-[50px] px-4 py-[2px]",
+ "mobile-tall": "min-h-[74px] px-4 py-[9px] xl:min-h-[45px] xl:py-[2px]",
+ wide: "min-h-[50px] px-4 py-[2px] xl:min-h-[45px]",
+ compact: "min-h-[50px] px-4 py-[2px]",
+};
+
+const promptTextClass =
+ "inline-block w-full break-words text-pretty font-mono text-[14px] font-normal leading-5 text-background-ppg-reverse-strong dark:text-foreground-ppg-reverse-weak";
+
+function BubbleTail({ side }: { side: "left" | "right" }) {
+ const positionClass =
+ side === "left"
+ ? "bottom-[-2px] left-[-10.5px]"
+ : "bottom-[-2px] right-[-10.5px] scale-x-[-1]";
+ const clipPathId = useId();
+
+ return (
+
+ );
+}
+
+export function McpPromptBubble({
+ variant,
+ children,
+}: {
+ variant: McpPromptBubbleVariant;
+ children: ReactNode;
+}) {
+ return (
+
+ );
+}
+
+export function McpBubble({
+ variant,
+ children,
+}: {
+ variant: McpBubbleVariant;
+ children: ReactNode;
+}) {
+ const { shell, tailSide } = config[variant];
+
+ return (
+
+ );
+}
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..6caf028030
--- /dev/null
+++ b/apps/site/src/app/mcp/_components/mcp-capabilities-section.tsx
@@ -0,0 +1,32 @@
+import { CapabilityCard } from "./capability-cards";
+
+export type McpCapability = {
+ icon: string;
+ title: string;
+ description: string;
+ prompt: string;
+ mobileTall: boolean;
+};
+
+export function McpCapabilitiesSection({
+ capabilities,
+}: {
+ capabilities: readonly McpCapability[];
+}) {
+ return (
+
+
+
+ What can I do with MCP?
+
+
+
+ {capabilities.map((cap, index) => {
+ const size = index < 2 ? "wide" : "compact";
+ return ;
+ })}
+
+
+
+ );
+}
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..05a3ff011e
--- /dev/null
+++ b/apps/site/src/app/mcp/_components/mcp-cta-section.tsx
@@ -0,0 +1,66 @@
+import { Button } from "@prisma/eclipse";
+
+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..6b1d33721b
--- /dev/null
+++ b/apps/site/src/app/mcp/_components/mcp-hero-section.tsx
@@ -0,0 +1,118 @@
+import type { ReactNode } from "react";
+
+import { Button } from "@prisma/eclipse";
+
+import { McpBubble } from "./mcp-bubble";
+import { McpTypeText } from "./mcp-type-text";
+
+export type McpHeroFeature = {
+ icon: string;
+ line1: string;
+ line2: string;
+ mobileText?: ReactNode;
+};
+
+const heroFeatureIconClass = "text-[24px] text-foreground-ppg";
+
+export function McpHeroSection({
+ docsHref,
+ features,
+}: {
+ docsHref: string;
+ features: readonly McpHeroFeature[];
+}) {
+ return (
+
+
+
+
+
+
+ Prisma MCP Server
+
+
+
+
+
+
+
+
+
+
+
+
+ _
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _
+
+
+
+
+
+
+
+
+
+
+
+ {features.map(({ icon, line1, line2, mobileText }) => (
+
+
+
+
+
+
+ {mobileText ?? `${line1} ${line2}`}
+
+
+ {line1}
+
+ {line2}
+
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/apps/site/src/app/mcp/_components/mcp-type-text.tsx b/apps/site/src/app/mcp/_components/mcp-type-text.tsx
new file mode 100644
index 0000000000..5345aa6466
--- /dev/null
+++ b/apps/site/src/app/mcp/_components/mcp-type-text.tsx
@@ -0,0 +1,43 @@
+"use client";
+
+import { useEffect, useState } from "react";
+
+export function McpTypeText({
+ text,
+ speed = 20,
+ delay = 0,
+ className,
+}: {
+ text: string;
+ speed?: number;
+ delay?: number;
+ className?: string;
+}) {
+ const [displayText, setDisplayText] = useState("");
+
+ useEffect(() => {
+ let index = 0;
+ let timer: ReturnType | null = null;
+ let startTimer: ReturnType | null = null;
+
+ setDisplayText("");
+
+ const typeNext = () => {
+ index += 1;
+ setDisplayText(text.slice(0, index));
+
+ if (index < text.length) {
+ timer = setTimeout(typeNext, speed);
+ }
+ };
+
+ startTimer = setTimeout(typeNext, delay);
+
+ return () => {
+ if (timer) clearTimeout(timer);
+ if (startTimer) clearTimeout(startTimer);
+ };
+ }, [delay, speed, text]);
+
+ return {displayText};
+}
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 (
+
+ );
+}
diff --git a/apps/site/src/app/mcp/page.tsx b/apps/site/src/app/mcp/page.tsx
new file mode 100644
index 0000000000..c5bbc7e633
--- /dev/null
+++ b/apps/site/src/app/mcp/page.tsx
@@ -0,0 +1,145 @@
+import type { Metadata } from "next";
+
+import {
+ type McpAgent,
+ McpAgentsSection,
+} from "./_components/mcp-agents-section";
+import {
+ type McpCapability,
+ McpCapabilitiesSection,
+} from "./_components/mcp-capabilities-section";
+import { McpCtaSection } from "./_components/mcp-cta-section";
+import {
+ type McpHeroFeature,
+ McpHeroSection,
+} from "./_components/mcp-hero-section";
+import { McpVideoSection } from "./_components/mcp-video-section";
+
+export const metadata: Metadata = {
+ title: "Prisma MCP Server",
+ description:
+ "Manage your databases with natural language via MCP in Claude, Codex, Cursor, Warp, ChatGPT, and other AI agents.",
+};
+
+const DOCS_MCP = "https://www.prisma.io/docs/postgres/integrations/mcp-server";
+
+const heroFeatures: McpHeroFeature[] = [
+ {
+ icon: "fa-light fa-message-smile",
+ line1: "Natural language",
+ line2: "database operations",
+ mobileText: (
+ <>
+ Natural language
+
+ db operations
+ >
+ ),
+ },
+ { icon: "fa-light fa-rocket-launch", line1: "Works with any", line2: "AI agent" },
+ { icon: "fa-light fa-bolt", line1: "Super quick", line2: "2-minute setup" },
+ { icon: "fa-light fa-lock", line1: "Enterprise-grade", line2: "security & OAuth" },
+];
+
+const agents: McpAgent[] = [
+ {
+ logo: "/mcp/logos/cursor.svg",
+ alt: "Add to Cursor",
+ icon: "fa-regular fa-copy",
+ href: DOCS_MCP,
+ },
+ {
+ logo: "/mcp/logos/vscode.svg",
+ alt: "Install in VS Code",
+ icon: "fa-regular fa-copy",
+ href: DOCS_MCP,
+ },
+ {
+ logo: "/mcp/logos/warp.svg",
+ alt: "Copy JSON configuration",
+ icon: "fa-regular fa-copy",
+ href: DOCS_MCP,
+ },
+ {
+ logo: "/mcp/logos/chatgpt.svg",
+ alt: "See how to add the remote Prisma MCP server to ChatGPT",
+ icon: "fa-regular fa-arrow-up-right",
+ href: "https://pris.ly/gpt-prisma-mcp",
+ },
+ {
+ logo: "/mcp/logos/claude-code.svg",
+ alt: "Copy command to add to Claude Code",
+ icon: "fa-regular fa-copy",
+ href: DOCS_MCP,
+ },
+ {
+ logo: "/mcp/logos/windsurf.svg",
+ alt: "Add via Plugin Store",
+ icon: "fa-regular fa-arrow-up-right",
+ href: "https://pris.ly/windsurf-mcp",
+ },
+ {
+ logo: "/mcp/logos/gemini.svg",
+ alt: "Copy command to add to Gemini CLI",
+ icon: "fa-regular fa-copy",
+ href: DOCS_MCP,
+ },
+ {
+ logo: null,
+ alt: "Any AI agent",
+ icon: null,
+ href: DOCS_MCP,
+ },
+];
+
+const capabilities: McpCapability[] = [
+ {
+ icon: "fa-light fa-database",
+ title: "Database Management",
+ description: "Create projects, databases, or clean them up via natural language",
+ prompt: "Set up this project with a new database in us-east-1",
+ mobileTall: false,
+ },
+ {
+ icon: "fa-light fa-magnifying-glass-arrow-right",
+ title: "Data Analysis",
+ description: "Execute queries and analyze data through conversation",
+ prompt: "Show me all users who signed up this week and their activity levels",
+ mobileTall: true,
+ },
+ {
+ icon: "fa-light fa-code-compare",
+ title: "Schema Operations",
+ description: "Manage migrations and database structure changes",
+ prompt: "Check my migration status and create a new user preferences table",
+ mobileTall: false,
+ },
+ {
+ icon: "fa-light fa-folder-gear",
+ title: "Database Administration",
+ description: "Handle backups, connection strings, and multi-database workflows",
+ prompt: "Create a new database from the most recent backup to my product db",
+ mobileTall: false,
+ },
+ {
+ icon: "fa-light fa-arrow-progress",
+ title: "Development Workflow",
+ description: "Integrate database operations seamlessly into coding workflow",
+ prompt: "Open Prisma Studio and show me the data in my users table",
+ mobileTall: false,
+ },
+];
+
+export default function McpPage() {
+ return (
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/packages/eclipse/src/components/button.tsx b/packages/eclipse/src/components/button.tsx
index 061f56253c..cb39674e84 100644
--- a/packages/eclipse/src/components/button.tsx
+++ b/packages/eclipse/src/components/button.tsx
@@ -5,29 +5,36 @@ import { cn } from "../lib/cn";
const buttonVariants = cva(
"flex flex-row justify-center items-center rounded-square transition-all duration-50 cursor-pointer disabled:bg-background-neutral-weak! disabled:border-none! disabled:text-foreground-neutral-weaker! disabled:cursor-not-allowed disabled:shadow-none",
{
- variants: {
- variant: {
- ppg: "bg-background-ppg-reverse text-foreground-ppg-reverse hover:bg-background-ppg-reverse-strong shadow-box-low",
- orm: "bg-background-orm-reverse text-foreground-orm-reverse hover:bg-background-orm-reverse-strong shadow-box-low",
- "default-stronger": "bg-background-neutral text-foreground-neutral hover:bg-background-neutral-strong",
- default: "bg-background-default hover:bg-background-neutral border border-stroke-neutral hover:border-stroke-neutral-strong text-foreground-neutral shadow-box-low",
- "default-weaker": "bg-transparent hover:bg-background-neutral text-foreground-neutral",
- error: "bg-background-error-reverse text-foreground-error-reverse hover:bg-background-error-reverse-strong shadow-box-low",
- success: "bg-background-success-reverse text-foreground-success-reverse hover:bg-background-success-reverse-strong shadow-box-low",
- link: "text-foreground-neutral underline-offset-4 hover:underline focus-visible:ring-foreground-neutral",
+ variants: {
+ variant: {
+ ppg: "bg-background-ppg-reverse text-foreground-ppg-reverse hover:bg-background-ppg-reverse-strong shadow-box-low",
+ orm: "bg-background-orm-reverse text-foreground-orm-reverse hover:bg-background-orm-reverse-strong shadow-box-low",
+ "default-stronger":
+ "bg-background-neutral text-foreground-neutral hover:bg-background-neutral-strong",
+ default:
+ "bg-background-default hover:bg-background-neutral border border-stroke-neutral hover:border-stroke-neutral-strong text-foreground-neutral shadow-box-low",
+ "default-weaker":
+ "bg-transparent hover:bg-background-neutral text-foreground-neutral",
+ error:
+ "bg-background-error-reverse text-foreground-error-reverse hover:bg-background-error-reverse-strong shadow-box-low",
+ success:
+ "bg-background-success-reverse text-foreground-success-reverse hover:bg-background-success-reverse-strong shadow-box-low",
+ link: "text-foreground-neutral underline-offset-4 hover:underline focus-visible:ring-foreground-neutral",
+ },
+ size: {
+ lg: "px-2 h-element-lg type-text-sm-strong",
+ xl: "px-3 h-element-xl type-text-sm-strong",
+ "2xl": "px-3 h-element-2xl type-text-sm-strong",
+ "3xl": "px-4 h-element-3xl type-text-sm-strong",
+ "4xl": "px-4 h-element-4xl type-heading-md",
+ },
},
- size: {
- lg: "px-2 h-element-lg type-text-sm-strong",
- xl: "px-3 h-element-xl type-text-sm-strong",
- "2xl": "px-3 h-element-2xl type-text-sm-strong",
- "4xl": "px-4 h-element-4xl type-heading-md",
+ defaultVariants: {
+ variant: "default",
+ size: "lg",
},
},
- defaultVariants: {
- variant: "default",
- size: "lg",
- },
-});
+);
type ButtonBaseProps = VariantProps;
@@ -47,27 +54,27 @@ const Button = React.forwardRef<
HTMLButtonElement | HTMLAnchorElement,
ButtonProps
>(({ className, variant, size, href, ...props }, ref) => {
- const classNames = cn(buttonVariants({ variant, size, className }));
-
- if (href) {
- return (
- }
- href={href}
- {...(props as React.AnchorHTMLAttributes)}
- />
- );
- }
+ const classNames = cn(buttonVariants({ variant, size, className }));
+ if (href) {
return (
-