diff --git a/content/900-ai/index.mdx b/content/900-ai/index.mdx new file mode 100644 index 0000000000..03355fc6da --- /dev/null +++ b/content/900-ai/index.mdx @@ -0,0 +1,185 @@ +--- +title: 'Build faster with Prisma + AI' +metaTitle: 'AI' +metaDescription: 'AI' +staticLink: true +--- + +import { + Grid, + LinkCard, +} from '@site/src/components/GettingStarted'; + +import { + CardHeading, + HomepageCard, +} from '@site/src/components/ProductBlock'; + + +In the era of AI, where code is increasingly written by agents, ensuring clarity, type safety, and reliable infrastructure is essential. With 5+ years of leadership in the TypeScript ecosystem, Prisma ORM and Prisma Postgres provide the proven foundation for AI-assisted development. + +### Get started + +Run the following command to bootstrap your database with a prompt: + +```bash +npx prisma init --prompt "Create a habit tracker application" +``` + +### AI Coding Tools + +Prisma ORM and Prisma Postgres integrate seamlessly with your AI coding tools. Check out our documentation with tips and tricks for working with Prisma in various AI editors. + + + + + + + + + + +### MCP server + +With Prisma’s MCP server, your AI tool can take database actions on your behalf: Provisioning a new Prisma Postgres instance, creating database backups and executing SQL queries are just a few of its capabilities. + + + +```json +{ + "mcpServers": { + "Prisma-Remote": { + "command": "npx", + "args": ["-y", "mcp-remote", "https://mcp.prisma.io/mcp"] + } + } +} +``` + + +```bash +npx -y mcp-remote https://mcp.prisma.io/mcp +``` + + + + + + } + href={{ + text: "Read now", + url: "https://www.prisma.io/docs/postgres/integrations/mcp-server#tools" + }} + body={`Discover all the tools that make up the capabilities of the Prisma MCP server.`} +/> + + } + href={{ + text: "Read now", + url: "https://www.prisma.io/docs/postgres/integrations/mcp-server#integrating-in-ai-tools" + }} + body={`Learn how to integrate Prisma’s MCP server in your favorite AI tool, such as Cursor, Claude, Warp, and more.`} +/> + + } + href={{ + text: "Read now", + url: "https://www.prisma.io/blog/about-mcp-servers-and-how-we-built-one-for-prisma" + }} + body={`Read this technical deep dive about the MCP protocol and how we built the Prisma MCP server.`} +/> + + +### Resources + + + + } + href={{ + text: "Read now", + url: "https://www.prisma.io/blog/vibe-coding-with-limits-how-to-build-apps-in-the-age-of-ai" + }} + body={`Software development is rapidly changing with AI coding tools. This article shows how to harness productivity gains while staying in control — and why understanding your code still matters.`} +/> + + } + href={{ + text: "Read now", + url: "https://www.prisma.io/blog/vibe-coding-with-prisma-mcp-and-nextjs" + }} + body={`Learn how we used the Prisma MCP server to build a Next.js e-commerce app with AI. We also share tips for effective prompting and avoiding common pitfalls.`} +/> + + } + href={{ + text: "Read now", + url: "https://www.prisma.io/docs/guides/ai-sdk-nextjs" + }} + body={`Learn how to build a chat application using the Vercel AI SDK with Next.js and Prisma ORM to store chat sessions and messages in a Prisma Postgres database.`} +/> + + +### Integrations + + + + } + href={{ + text: "Get started", + url: "https://pipedream.com/apps/prisma-management-api" + }} + body={`Connect Prisma Postgres to other apps to create powerful automations and data workflows, such as automatically spinning up a new database when a customer signs up in Stripe or connecting your database with Slack, Notion, Airtable, or any other app in the Pipedream ecosystem.`} +/> + + } + href={{ + text: "Get started", + url: "https://www.prisma.io/docs/postgres/integrations/idx" + }} + body={`Google's Firebase Studio is a fully-fledged online IDE with a native AI integration. Prompt and build apps directly in your browser and deploy them by connecting with a powerful Prisma Postgres database in just a few clicks.`} +/> + diff --git a/docusaurus.config.ts b/docusaurus.config.ts index 5cbfce2236..5bc27295e3 100644 --- a/docusaurus.config.ts +++ b/docusaurus.config.ts @@ -315,6 +315,14 @@ const config: Config = { sub: "Make your database global", icon: "fa-regular fa-bolt" }, + { + type: "docSidebar", + className: "teal", + sidebarId: "aiSidebar", + label: "Prisma + AI", + sub: "Build faster with Prisma + AI", + icon: "fa-regular fa-robot" + }, ], }, { diff --git a/sidebars.ts b/sidebars.ts index 700f61b046..09217f0e48 100644 --- a/sidebars.ts +++ b/sidebars.ts @@ -511,6 +511,98 @@ const sidebars: SidebarsConfig = { ], }, ], + aiSidebar: [ + { + type: "category", + label: "Prisma + AI", + collapsed: false, + collapsible: false, + link: { + type: "doc", + id: "ai/index", + }, + className: "firstTitle", + items: [ + { + type: "category", + label: "Coding Tools", + collapsed: false, + collapsible: false, + items: [ + "orm/more/ai-tools/cursor", + "orm/more/ai-tools/windsurf", + "orm/more/ai-tools/github-copilot", + "orm/more/ai-tools/tabnine", + ], + }, + { + type: "category", + label: "MCP Server", + collapsed: false, + collapsible: false, + items: [ + { + type: "link", + label: "Capabilities and Tools", + href: "/postgres/integrations/mcp-server#tools" + }, + { + type: "link", + label: "Integrating in AI tools", + href: "/postgres/integrations/mcp-server#integrating-in-ai-tools" + }, + { + type: "link", + label: "How we built it", + href: "https://www.prisma.io/blog/about-mcp-servers-and-how-we-built-one-for-prisma" + }, + ], + }, + { + type: "category", + label: "Resources", + collapsed: false, + collapsible: false, + items: [ + { + type: "link", + label: "How to Build Apps in the Age of AI", + href: "https://www.prisma.io/blog/vibe-coding-with-limits-how-to-build-apps-in-the-age-of-ai" + }, + { + type: "link", + label: "Vibe Coding an E-commerce App with Prisma MCP and Next.js", + href: "https://www.prisma.io/blog/vibe-coding-with-prisma-mcp-and-nextjs" + }, + { + type: "link", + label: "Integrating the Vercel AI SDK in a Next.js application", + href: "/guides/ai-sdk-nextjs" + }, + ], + }, + { + type: "category", + label: "Integrations", + collapsed: false, + collapsible: false, + items: [ + { + type: "link", + label: "Automate your workflows with Prisma Postgres and 2,800+ apps", + href: "https://pipedream.com/apps/prisma-management-api" + }, + { + type: "link", + label: "Prompt your application with Firebase Studio & Prisma Postgres", + href: "/postgres/integrations/idx" + }, + ], + }, + // { type: "autogenerated", dirName: "900-ai" } + ] + }, + ] }; export default sidebars; diff --git a/src/components/ProductBlock/index.module.scss b/src/components/ProductBlock/index.module.scss new file mode 100644 index 0000000000..2d89b5ba96 --- /dev/null +++ b/src/components/ProductBlock/index.module.scss @@ -0,0 +1,160 @@ + +.linkGrid { + display: flex; + max-width: 338px; + gap: 16px; + width: 100%; + flex-wrap: wrap; + justify-content: space-between; + height: fit-content; + + a, + button { + min-width: calc(50% - 8px); + white-space: nowrap; + font-family: "Inter"; + font-size: 16px; + font-style: normal; + font-weight: 600; + line-height: 100%; + /* 16px */ + letter-spacing: -0.32px; + text-decoration: none; + + &:hover { + text-decoration: underline; + } + } + + svg { + display: none; + } +} + +%productCard { + padding: 24px; + width: 100%; + border-radius: 8px; + box-shadow: 0px 0px 2px 0px rgba(23, 43, 77, 0.04), 0px 3px 2px 0px rgba(23, 43, 77, 0.08); + background: var(--card-bg); + transition: all 200ms ease-in-out; + outline: 1px solid var(--border-color); + h4 { + margin: 0; + font-size: 20px; + } + .body { + margin-top: 20px; + overflow: hidden; + font-size: 18px; + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + } + &:hover { + box-shadow: 0px 18px 42px 0px #172B4D14, + 0px 4px 26px 0px #172B4D0D, + 0px 0px 46px 0px #172B4D03; + } + button { + font-size: 18px; + margin-top: 16px; + } + &.light { + display: grid; + height: 100%; + grid-template-rows: auto 1fr auto; + } +} + +.productCardTeal { + @extend %productCard; + &:hover { + outline: 2px solid var(--teal-600); + } + h5.eyebrow { + color: var(--teal-600); + } + + a, + button { + color: var(--teal-link-color); + } + + .icon, .iconWrapper { + background: var(--teal-600); + &.light { + background: var(--surface-brand-light); + } + } +} +.cardHeader { + display: flex; + gap: 24px; + align-items: center; + min-height: 81px; + h5.eyebrow { + margin-bottom: 8px; + } + &.light { + gap: 16px; + } + .iconWrapper { + width: 64px; + height: 64px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 10.5px; + flex-shrink: 0; + } +} + +h5.eyebrow { + //styleName: HEADINGS/H5; + font-family: "Barlow"; + font-size: 18px; + font-weight: 700; + line-height: 110%; + margin: 0; + text-transform: uppercase; + color: var(--tertiary-font-color); + letter-spacing: 0.1em; + text-align: left; +} + +.h4 { + font-family: "Barlow"; + margin: 0; + font-size: 24px; + font-style: normal; + font-weight: 700; + line-height: 110%; + /* 26.4px */ + letter-spacing: -0.48px; +} +.light .h4 { + font-size: 20px; +} +.body { + font-family: + "Inter", + system-ui, + -apple-system, + BlinkMacSystemFont, + "Segoe UI", + Roboto, + "Helvetica Neue", + Arial, + "Noto Sans", + sans-serif, + "Apple Color Emoji", + "Segoe UI Emoji", + "Segoe UI Symbol", + "Noto Color Emoji"; + font-weight: normal; + font-size: 16px; + letter-spacing: 0em; + line-height: 140%; + color: var(--secondary-font-color); +} diff --git a/src/components/ProductBlock/index.tsx b/src/components/ProductBlock/index.tsx new file mode 100644 index 0000000000..e5b77c375e --- /dev/null +++ b/src/components/ProductBlock/index.tsx @@ -0,0 +1,85 @@ +import { JSX } from "react"; +import { useLocation } from "@docusaurus/router"; +import Link from "@docusaurus/Link"; +import styles from "./index.module.scss" +import { Icon } from "@site/src/components/Icon"; +import Heading from "@theme/Heading"; +import clsx from "clsx"; +import Button from "../button/Button"; + +export function HomepageCard({ + className, + heading, + body, + link, + indigo, + links, + light, + href, + ...rest +}: { + className?: string; + heading: JSX.Element; + body: string; + links?: JSX.Element; + link?: string; + light?: boolean; + indigo?: boolean; + href?: { + text: string, + url: string, + } +}): JSX.Element { + const location = useLocation(); + const f_class = clsx(className, styles.productCardTeal, light && styles.light); + return ( + link + ? + {heading} +
+ + :
+ {heading} +
+ {href && href.url &&
+ ); +} + +interface CardHeadingProps { + eyebrow?: string; + icon: string; + title: string; + light?: boolean; +} + +export const Grid = ({ children, className }: { children?: React.ReactNode; className?: string }) => ( +
{children}
+) + +export const CardHeading = ({ eyebrow, icon, title, light }: CardHeadingProps) => { + return ( +
+
+ +
+
+ {eyebrow &&
{eyebrow}
} + +
+ +
+
+ ) +} + diff --git a/src/css/all.css b/src/css/all.css index d5b3294268..5884f6d44c 100644 --- a/src/css/all.css +++ b/src/css/all.css @@ -848,10 +848,6 @@ content: "\f60f"; } -.fa-openai::before { - content: "\e7cf"; -} - .fa-globe::before { content: "\f0ac"; } @@ -1000,6 +996,26 @@ content: "\f0ce"; } +.fa-screwdriver-wrench::before { + content: "\f7d9"; +} + +.fa-gear::before { + content: "\f013"; +} + +.fa-lightbulb::before { + content: "\f0eb"; +} + +.fa-message-dots::before { + content: "\f4a3"; +} + +.fa-wand-magic-sparkles::before { + content: "\e2ca"; +} + .sr-only, .fa-sr-only { position: absolute; @@ -1093,6 +1109,29 @@ content: "\e61b"; } +.fa-openai::before, .fa-cursor::before, .fa-windsurf::before, .fa-tabnine::before { + display: inline-block; + width: 24px; + height: 24px; +} + +.fa-openai::before { + content: url("/icons/openai.svg"); +} +.fa-cursor::before { + content: url("/icons/cursor.svg"); +} +.fa-windsurf::before { + content: url("/icons/windsurf.svg"); +} +.fa-tabnine::before { + content: url("/icons/tabnine.svg"); +} + +[data-theme="dark"] .fa-openai, [data-theme="dark"] .fa-cursor, [data-theme="dark"] .fa-windsurf { + filter: invert(1); +} + /*! * Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com * License - https://fontawesome.com/license (Commercial License) diff --git a/src/css/custom.css b/src/css/custom.css index 5a8e41a75e..fa03f5730f 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -1497,7 +1497,6 @@ article h3, article h4, article h5, article h6 { - font-size: revert; font-family: "Inter", sans-serif; color: var(--main-font-color); font-weight: 600; diff --git a/src/css/gettingStarted.module.scss b/src/css/gettingStarted.module.scss index 0226c685bc..14fdb997a2 100644 --- a/src/css/gettingStarted.module.scss +++ b/src/css/gettingStarted.module.scss @@ -94,7 +94,7 @@ } } .title { - display: inline-block; + display: inline-flex; h6 { font-size: 18px; display: inline-block; diff --git a/src/pages/index.module.scss b/src/pages/index.module.scss index 6348730560..b14465c88d 100644 --- a/src/pages/index.module.scss +++ b/src/pages/index.module.scss @@ -237,72 +237,6 @@ } } -.h4 { - font-family: "Barlow"; - margin: 0; - font-size: 24px; - font-style: normal; - font-weight: 700; - line-height: 110%; - /* 26.4px */ - letter-spacing: -0.48px; -} - -.body { - font-family: - "Inter", - system-ui, - -apple-system, - BlinkMacSystemFont, - "Segoe UI", - Roboto, - "Helvetica Neue", - Arial, - "Noto Sans", - sans-serif, - "Apple Color Emoji", - "Segoe UI Emoji", - "Segoe UI Symbol", - "Noto Color Emoji"; - font-weight: normal; - font-size: 16px; - letter-spacing: 0em; - line-height: 140%; - color: var(--secondary-font-color); -} - -.linkGrid { - display: flex; - max-width: 338px; - gap: 16px; - width: 100%; - flex-wrap: wrap; - justify-content: space-between; - height: fit-content; - - a, - button { - min-width: calc(50% - 8px); - white-space: nowrap; - font-family: "Inter"; - font-size: 16px; - font-style: normal; - font-weight: 600; - line-height: 100%; - /* 16px */ - letter-spacing: -0.32px; - text-decoration: none; - - &:hover { - text-decoration: underline; - } - } - - svg { - display: none; - } -} - .productCardsWrapper { max-width: 1240px; padding: 0 8px; @@ -320,83 +254,8 @@ @media (min-width: 974px) { grid-template-columns: repeat(3, 1fr); } - .cardHeader { - display: flex; - gap: 24px; - align-items: center; - min-height: 81px; - h5.eyebrow { - margin-bottom: 8px; - } - .iconWrapper { - width: 64px; - height: 64px; - display: flex; - align-items: center; - justify-content: center; - border-radius: 10.5px; - flex-shrink: 0; - } - } -} - -h5.eyebrow { - //styleName: HEADINGS/H5; - font-family: "Barlow"; - font-size: 18px; - font-weight: 700; - line-height: 110%; - margin: 0; - text-transform: uppercase; - color: var(--tertiary-font-color); - letter-spacing: 0.1em; - text-align: left; } -%productCard { - padding: 24px; - width: 100%; - border-radius: 8px; - box-shadow: 0px 0px 2px 0px rgba(23, 43, 77, 0.04), 0px 3px 2px 0px rgba(23, 43, 77, 0.08); background: var(--card-bg); - transition: all 200ms ease-in-out; - outline: 1px solid var(--border-color); - h4 { - margin: 0; - font-size: 20px; - } - .body { - margin-top: 20px; - overflow: hidden; - font-size: 18px; - display: -webkit-box; - -webkit-line-clamp: 3; - -webkit-box-orient: vertical; - } - &:hover { - box-shadow: 0px 18px 42px 0px #172B4D14, - 0px 4px 26px 0px #172B4D0D - 0px 0px 46px 0px #172B4D03; - } -} - -.productCardTeal { - @extend %productCard; - &:hover { - outline: 2px solid var(--teal-600); - } - h5.eyebrow { - color: var(--teal-600); - } - - a, - button { - color: var(--teal-link-color); - } - - .icon, .iconWrapper { - background: var(--teal-600); - } -} @keyframes fadeIn { to { diff --git a/src/pages/index.tsx b/src/pages/index.tsx index d0523159ef..7f2c3a2c94 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -8,43 +8,14 @@ import { CommunityLinksData, get_help, how_do_i, ProductLinkData, tabs } from "@ import Heading from "@theme/Heading"; import Layout from "@theme/Layout"; import clsx from "clsx"; -import { useEffect, useRef, useState } from "react"; +import { useRef, useState } from "react"; import Badge from "../components/button/Badge"; import { SquareLogo } from "../components/GettingStarted"; import { Tooltip } from "../components/tooltip/Tooltip"; import CodeBlock from "../theme/CodeBlock"; import styles from "./index.module.scss"; - -function HomepageCard({ - className, - heading, - body, - link, - links, - ...rest -}: { - className: string; - heading: JSX.Element; - body: JSX.Element; - links?: JSX.Element; - link?: string; -}): JSX.Element { - const location = useLocation(); - return ( - link - ? - {heading} - {body} - - :
- {heading} - {body} -
{links}
-
- - ); -} +import { CardHeading, HomepageCard } from "../components/ProductBlock"; function HomepageProductCards() { return ( @@ -53,33 +24,17 @@ function HomepageProductCards() { Products
{Object.keys(ProductLinkData).map((e: keyof typeof ProductLinkData) => { - const cardHeader = ( -
-
- -
-
-
{ProductLinkData[e].eyebrow}
- -
-
-
-
- ); - const cardBody = ( -
- ); + const cardHeader = + ; return ( ); diff --git a/src/theme/DocSidebarItem/Link/index.tsx b/src/theme/DocSidebarItem/Link/index.tsx index 9e81e8d221..d54a40dcb0 100644 --- a/src/theme/DocSidebarItem/Link/index.tsx +++ b/src/theme/DocSidebarItem/Link/index.tsx @@ -1,12 +1,14 @@ -import React, { useEffect, useState } from "react"; -import clsx from "clsx"; -import { isActiveSidebarItem } from "@docusaurus/plugin-content-docs/client"; -import { ThemeClassNames } from "@docusaurus/theme-common"; -import Link from "@docusaurus/Link"; import isInternalUrl from "@docusaurus/isInternalUrl"; -import styles from "./styles.module.css"; +import Link from "@docusaurus/Link"; +import { isActiveSidebarItem } from "@docusaurus/plugin-content-docs/client"; import { useLocation } from "@docusaurus/router"; +import { ThemeClassNames } from "@docusaurus/theme-common"; import { Icon } from "@site/src/components/Icon"; +import clsx from "clsx"; +import React, { useEffect, useState } from "react"; + +import styles from "./styles.module.css"; + export default function DocSidebarItemLink({ item, onItemClick, @@ -77,8 +79,8 @@ export default function DocSidebarItemLink({ {...props} > {label} + {!isInternalLink && " ↗"} {badgeContent && {badgeContent}} - {!isInternalLink && } ); diff --git a/src/theme/TOC/styles.module.css b/src/theme/TOC/styles.module.css index cf33015ab2..ceb2110bee 100644 --- a/src/theme/TOC/styles.module.css +++ b/src/theme/TOC/styles.module.css @@ -3,6 +3,7 @@ position: sticky; top: calc(var(--ifm-navbar-height) + 1rem); overflow: auto; + min-height: 240px; } .tableOfContents { diff --git a/static/icons/cursor.svg b/static/icons/cursor.svg new file mode 100644 index 0000000000..62e53701db --- /dev/null +++ b/static/icons/cursor.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/static/icons/openai.svg b/static/icons/openai.svg new file mode 100644 index 0000000000..cdc3136f81 --- /dev/null +++ b/static/icons/openai.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/icons/tabnine.svg b/static/icons/tabnine.svg new file mode 100644 index 0000000000..bd7cf241e7 --- /dev/null +++ b/static/icons/tabnine.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/icons/windsurf.svg b/static/icons/windsurf.svg new file mode 100644 index 0000000000..dd7f0a96b9 --- /dev/null +++ b/static/icons/windsurf.svg @@ -0,0 +1,3 @@ + + +