diff --git a/apps/docs/.gitignore b/apps/docs/.gitignore index ca8ec6b88b967..f27e790639814 100644 --- a/apps/docs/.gitignore +++ b/apps/docs/.gitignore @@ -44,6 +44,8 @@ public/docs/ # scripts/federated-content/fetch-federated-content.ts /content/guides/graphql/ /content/guides/graphql.mdx +/content/guides/deployment/terraform.mdx +/content/guides/deployment/terraform/tutorial.mdx # Downloaded TypeDoc dumps under spec/reference///. Regenerated by # `cd apps/docs/spec && make download.tsdoc.v2`. Hand-authored files in the diff --git a/apps/docs/app/guides/deployment/terraform/[[...slug]]/page.tsx b/apps/docs/app/guides/deployment/terraform/[[...slug]]/page.tsx index 153c814eff369..d30e3452ce5cf 100644 --- a/apps/docs/app/guides/deployment/terraform/[[...slug]]/page.tsx +++ b/apps/docs/app/guides/deployment/terraform/[[...slug]]/page.tsx @@ -1,152 +1,26 @@ -import { GuideTemplate, newEditLink } from '~/features/docs/GuidesMdx.template' -import { genGuideMeta, removeRedundantH1 } from '~/features/docs/GuidesMdx.utils' +import { GuideTemplate } from '~/features/docs/GuidesMdx.template' +import { + genGuideMeta, + genGuidesStaticParams, + getGuidesMarkdown, +} from '~/features/docs/GuidesMdx.utils' import { getEmptyArray } from '~/features/helpers.fn' import { IS_DEV } from '~/lib/constants' -import { isValidGuideFrontmatter } from '~/lib/docs' -import { linkTransform, UrlTransformFunction } from '~/lib/mdx/plugins/rehypeLinkTransform' -import remarkMkDocsAdmonition from '~/lib/mdx/plugins/remarkAdmonition' -import { removeTitle } from '~/lib/mdx/plugins/remarkRemoveTitle' -import remarkPyMdownTabs from '~/lib/mdx/plugins/remarkTabs' -import { getGitHubFileContents } from '~/lib/octokit' -import { SerializeOptions } from '~/types/next-mdx-remote-serialize' -import matter from 'gray-matter' -import { notFound } from 'next/navigation' -import rehypeSlug from 'rehype-slug' - -import { - terraformDocsBranch, - terraformDocsDocsDir, - terraformDocsOrg, - terraformDocsRepo, -} from '../terraformConstants' -// Each external docs page is mapped to a local page -const pageMap = [ - { - remoteFile: 'README.md', - meta: { - title: 'Terraform Provider', - }, - useRoot: true, - }, - { - slug: 'tutorial', - remoteFile: 'tutorial.md', - meta: { - title: 'Using the Supabase Terraform Provider', - }, - }, -] - -interface Params { - slug?: string[] -} +type Params = { slug?: string[] } const TerraformDocs = async (props: { params: Promise }) => { const params = await props.params - const { meta, ...data } = await getContent(params) - - const options = { - mdxOptions: { - remarkPlugins: [remarkMkDocsAdmonition, remarkPyMdownTabs, [removeTitle, meta.title]], - rehypePlugins: [[linkTransform, urlTransform], rehypeSlug], - }, - } as SerializeOptions - - return -} - -/** - * The GitHub repo uses relative links, which don't lead to the right locations - * in docs. - * - * @param url The original link, as written in the Markdown file - * @returns The rewritten link - */ -const urlTransform: UrlTransformFunction = (url: string) => { - try { - const placeholderHostname = 'placeholder' - const { hostname, pathname, hash } = new URL(url, `http://${placeholderHostname}`) - - // Don't modify a url with a FQDN or a url that's only a hash - if (hostname !== placeholderHostname || pathname === '/') { - return url - } - - const getBasename = (pathname: string) => - pathname.endsWith('.md') ? pathname.replace(/\.md$/, '') : pathname - const stripLeadingPrefix = (pathname: string) => pathname.replace(/^\//, '') - const stripLeadingDocs = (pathname: string) => pathname.replace(/^docs\//, '') - - const relativePath = stripLeadingPrefix(getBasename(pathname)) - - const page = pageMap.find( - ({ remoteFile, useRoot }) => - (useRoot && `${relativePath}.md` === remoteFile) || - (!useRoot && `${stripLeadingDocs(relativePath)}.md` === remoteFile) - ) - - if (page) { - return 'terraform' + `/${page.slug}` + hash - } - - // If we don't have this page in our docs, link to GitHub repo - return `https://github.com/${terraformDocsOrg}/${terraformDocsRepo}/blob/${terraformDocsBranch}${pathname}${hash}` - } catch (err) { - console.error('Error transforming markdown URL', err) - return url - } -} - -/** - * Fetch markdown from external repo - */ -const getContent = async ({ slug }: Params) => { - const [requestedSlug] = slug ?? [] - const page = pageMap.find((page) => page.slug === requestedSlug) - - if (!page) { - notFound() - } - - const { meta, remoteFile, useRoot } = page - - const editLink = newEditLink( - `${terraformDocsOrg}/${terraformDocsRepo}/blob/${terraformDocsBranch}/${useRoot ? '' : `${terraformDocsDocsDir}/`}${remoteFile}` - ) - - let rawContent = await getGitHubFileContents({ - org: terraformDocsOrg, - repo: terraformDocsRepo, - path: useRoot ? remoteFile : `${terraformDocsDocsDir}/${remoteFile}`, - branch: terraformDocsBranch, - }) - // Strip out HTML comments - rawContent = rawContent.replace(//, '') - let { content, data } = matter(rawContent) - - // Remove the title from the content so it isn't duplicated in the final display - content = removeRedundantH1(content) - - Object.assign(meta, data) - - if (!isValidGuideFrontmatter(meta)) { - throw Error('Guide frontmatter is invalid.') - } + const slug = ['deployment', 'terraform', ...(params.slug ?? [])] + const data = await getGuidesMarkdown(slug) - return { - pathname: - `/guides/deployment/terraform${slug?.length ? `/${slug.join('/')}` : ''}` satisfies `/${string}`, - meta, - content, - editLink, - } + return } -const generateStaticParams = !IS_DEV - ? async () => pageMap.map(({ slug }) => ({ slug: slug ? [slug] : [] })) - : getEmptyArray -const generateMetadata = genGuideMeta(getContent) +const generateStaticParams = !IS_DEV ? genGuidesStaticParams('deployment/terraform') : getEmptyArray +const generateMetadata = genGuideMeta((params: { slug?: string[] }) => + getGuidesMarkdown(['deployment', 'terraform', ...(params.slug ?? [])]) +) export default TerraformDocs -export { generateMetadata, generateStaticParams } +export { generateStaticParams, generateMetadata } diff --git a/apps/docs/app/guides/deployment/terraform/terraformConstants.ts b/apps/docs/app/guides/deployment/terraform/terraformConstants.ts deleted file mode 100644 index 0cc7ad3125bb1..0000000000000 --- a/apps/docs/app/guides/deployment/terraform/terraformConstants.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Information on where to fetch docs content - */ -const terraformDocsOrg = 'supabase' -const terraformDocsRepo = 'terraform-provider-supabase' -const terraformDocsBranch = 'v1.1.3' -const terraformDocsDocsDir = 'docs' - -export { terraformDocsOrg, terraformDocsRepo, terraformDocsBranch, terraformDocsDocsDir } diff --git a/apps/docs/app/page.tsx b/apps/docs/app/page.tsx index 31eba97aef4e2..031a06a61a47b 100644 --- a/apps/docs/app/page.tsx +++ b/apps/docs/app/page.tsx @@ -5,6 +5,7 @@ import { cn } from 'ui' import { IconPanel } from 'ui-patterns/IconPanel' import { TextLink } from 'ui-patterns/TextLink' +import { FrameworkQuickstarts } from '@/components/HomePageCover' import { MIGRATION_PAGES } from '@/components/Navigation/NavigationMenu/NavigationMenu.constants' import { GlassPanelWithIconPicker } from '@/features/ui/GlassPanelWithIconPicker' import { IconPanelWithIconPicker } from '@/features/ui/IconPanelWithIconPicker' @@ -45,7 +46,7 @@ const products = [ href: '/guides/database/overview', description: 'Supabase provides a full Postgres database for every project with Realtime functionality, database backups, extensions, and more.', - span: 'col-span-12 md:col-span-6', + span: 'col-span-12', }, { title: 'Auth', @@ -226,26 +227,55 @@ const additionalResources = [ const HomePage = () => (
-

Products

-
    - {products.map((product) => { - return ( -
  • - - - {product.description} - - -
  • - ) - })} -
+ {isFeatureEnabled('docs:full_getting_started') && ( +
+
+

+ Connect a framework +

+

+ Start with a framework quickstart and connect your project in minutes. +

+
+ +
+ +
+
+ )} +
+
+

+ Build your backend +

+

+ Build with a complete backend platform, from your database to your application logic. +

+
-
-
-

- Modules +
    + {products.map((product) => { + return ( +
  • + + + {product.description} + + +
  • + ) + })} +
+

+ +
+
+

+ Extend your database

+

+ Extend your database with built-in tools for AI, APIs, scheduled jobs, and queues. +

{postgresIntegrations.map((integration) => ( @@ -261,15 +291,14 @@ const HomePage = () => (
-
+
-
-
-

- Client Libraries -

-
-
+

+ Use a client library +

+

+ Use Supabase from the language and framework your application is built with. +

@@ -291,7 +320,7 @@ const HomePage = () => (
{isFeatureEnabled('docs:full_getting_started') && ( -
+

Migrate to Supabase @@ -322,20 +351,22 @@ const HomePage = () => (

)} -
-
-

- Additional resources +
+
+

+ Explore more

+

+ Explore the tools, integrations, and guides that help you get more from Supabase. +

-
    +
      {additionalResources.map((resource) => { return ( -
    • +
    • @@ -349,12 +380,12 @@ const HomePage = () => (
{isFeatureEnabled('docs:full_getting_started') && ( -
+

- Self-Hosting + Self-host Supabase

diff --git a/apps/docs/components/DocsCoverLogo.tsx b/apps/docs/components/DocsCoverLogo.tsx index 3b56575513fc5..eebc87c0092b9 100644 --- a/apps/docs/components/DocsCoverLogo.tsx +++ b/apps/docs/components/DocsCoverLogo.tsx @@ -1,9 +1,9 @@ 'use client' import { domAnimation, LazyMotion, m } from 'framer-motion' -import React, { type PropsWithChildren } from 'react' +import React, { type ComponentPropsWithoutRef } from 'react' -const DocsCoverLogo = (props: PropsWithChildren) => { +const DocsCoverLogo = ({ className, ...props }: ComponentPropsWithoutRef<'div'>) => { const pathMotionConfig = { initial: { pathLength: 0 }, animate: { pathLength: 1 }, @@ -24,7 +24,7 @@ const DocsCoverLogo = (props: PropsWithChildren) => { } return ( -

+
- - Start with Supabase AI prompts - - + + + }>AI Prompt + {setupPrompt} + + Help me get set up with Supabase. Do the following: 1. Install the Supabase CLI globally + with{' '} + + {setupCommand.installCli} + + . 2. Install the Supabase Plugin with{' '} + + {setupCommand.installPlugin} + + . 3. Review my project and determine whether Supabase is already initialized. If it is not + initialized, run{' '} + + {setupCommand.initialize} + + . 4. Suggest the most relevant next steps. + + + + }>CLI + {setupCommands} + {cliCode} + + ) } -const HomePageCover = (props) => { +const frameworks = [ + { + tooltip: 'ReactJS', + icon: '/docs/img/icons/react-icon', + href: '/guides/getting-started/quickstarts/reactjs', + hasLightIcon: false, + }, + { + tooltip: 'Next.js', + icon: '/docs/img/icons/nextjs-icon', + href: '/guides/getting-started/quickstarts/nextjs', + hasLightIcon: false, + }, + { + tooltip: 'TanStack Start', + icon: '/docs/img/icons/tanstack-icon', + href: '/guides/getting-started/quickstarts/tanstack', + hasLightIcon: true, + }, + { + tooltip: 'Astro.js', + icon: '/docs/img/icons/astro-icon', + href: '/guides/getting-started/quickstarts/astrojs', + hasLightIcon: true, + }, + { + tooltip: 'Vue', + icon: '/docs/img/icons/vuejs-icon', + href: '/guides/getting-started/quickstarts/vue', + hasLightIcon: false, + }, + { + tooltip: 'Nuxt', + icon: '/docs/img/icons/nuxt-icon', + href: '/guides/getting-started/quickstarts/nuxtjs', + hasLightIcon: false, + }, + { + tooltip: 'iOS Swift', + icon: '/docs/img/icons/swift-icon-orange', + href: '/guides/getting-started/quickstarts/ios-swiftui', + enabled: sdkSwiftEnabled, + hasLightIcon: false, + }, + { + tooltip: 'Android Kotlin', + icon: '/docs/img/icons/kotlin-icon', + href: '/guides/getting-started/quickstarts/kotlin', + enabled: sdkKotlinEnabled, + hasLightIcon: false, + }, + { + tooltip: 'Expo React Native', + icon: '/docs/img/icons/expo-icon', + href: '/guides/getting-started/quickstarts/expo-react-native', + hasLightIcon: true, + }, + { + tooltip: 'Flutter', + icon: '/docs/img/icons/flutter-icon', + href: '/guides/getting-started/quickstarts/flutter', + enabled: sdkDartEnabled, + hasLightIcon: false, + }, + { + tooltip: 'Python', + icon: '/docs/img/icons/python-icon', + href: '/guides/getting-started/quickstarts/flask', + hasLightIcon: false, + }, +] + +export function FrameworkQuickstarts() { const isXs = useBreakpoint(639) const iconSize = isXs ? 'sm' : 'lg' - const { homepageHeading } = getCustomContent(['homepage:heading']) const { resolvedTheme } = useTheme() - const isLightMode = !resolvedTheme?.includes('dark') + const [isMounted, setIsMounted] = useState(false) + const isLightMode = isMounted && resolvedTheme === 'light' - const frameworks = [ - { - tooltip: 'ReactJS', - icon: '/docs/img/icons/react-icon', - href: '/guides/getting-started/quickstarts/reactjs', - hasLightIcon: false, - }, - { - tooltip: 'Next.js', - icon: '/docs/img/icons/nextjs-icon', - href: '/guides/getting-started/quickstarts/nextjs', - hasLightIcon: false, - }, - { - tooltip: 'TanStack Start', - icon: '/docs/img/icons/tanstack-icon', - href: '/guides/getting-started/quickstarts/tanstack', - hasLightIcon: true, - }, - { - tooltip: 'Astro.js', - icon: '/docs/img/icons/astro-icon', - href: '/guides/getting-started/quickstarts/astrojs', - hasLightIcon: true, - }, - { - tooltip: 'Vue', - icon: '/docs/img/icons/vuejs-icon', - href: '/guides/getting-started/quickstarts/vue', - hasLightIcon: false, - }, - { - tooltip: 'Nuxt', - icon: '/docs/img/icons/nuxt-icon', - href: '/guides/getting-started/quickstarts/nuxtjs', - hasLightIcon: false, - }, - { - tooltip: 'iOS Swift', - icon: '/docs/img/icons/swift-icon-orange', - href: '/guides/getting-started/quickstarts/ios-swiftui', - enabled: sdkSwiftEnabled, - hasLightIcon: false, - }, - { - tooltip: 'Android Kotlin', - icon: '/docs/img/icons/kotlin-icon', - href: '/guides/getting-started/quickstarts/kotlin', - enabled: sdkKotlinEnabled, - hasLightIcon: false, - }, - { - tooltip: 'Expo React Native', - icon: '/docs/img/icons/expo-icon', - href: '/guides/getting-started/quickstarts/expo-react-native', - hasLightIcon: true, - }, - { - tooltip: 'Flutter', - icon: '/docs/img/icons/flutter-icon', - href: '/guides/getting-started/quickstarts/flutter', - enabled: sdkDartEnabled, - hasLightIcon: false, - }, - { - tooltip: 'Python', - icon: '/docs/img/icons/python-icon', - href: '/guides/getting-started/quickstarts/flask', - hasLightIcon: false, - }, - ] + useEffect(() => setIsMounted(true), []) - const GettingStarted = () => ( -
-
-
-
-

Getting Started

-

- Set up and connect a database in just a few minutes. -

-
-
-
-
- {frameworks - .filter((framework) => framework.enabled !== false) - .map((framework, i) => { - const iconToUse = - framework.hasLightIcon && isLightMode ? `${framework.icon}-light` : framework.icon + return ( +
+ {frameworks + .filter((framework) => framework.enabled !== false) + .map((framework) => { + const iconToUse = + framework.hasLightIcon && isLightMode ? `${framework.icon}-light` : framework.icon - return ( - - - - ) - })} -
- -
-
+ return ( + + + + ) + })}
) +} + +const HomePageCover = ({ title, cliCode }: { title: string; cliCode: ReactNode }) => { + const { homepageHeading } = getCustomContent(['homepage:heading']) return ( -
-
-
-