Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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: 2 additions & 0 deletions apps/docs/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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/<lib>/<ver>/. Regenerated by
# `cd apps/docs/spec && make download.tsdoc.v2`. Hand-authored files in the
Expand Down
156 changes: 15 additions & 141 deletions apps/docs/app/guides/deployment/terraform/[[...slug]]/page.tsx
Original file line number Diff line number Diff line change
@@ -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<Params> }) => {
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 <GuideTemplate mdxOptions={options} meta={meta} {...data} />
}

/**
* 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 <GuideTemplate {...data!} />
}

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 }

This file was deleted.

105 changes: 68 additions & 37 deletions apps/docs/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -226,26 +227,55 @@ const additionalResources = [
const HomePage = () => (
<HomeLayout>
<div className="flex flex-col">
<h2 id="products">Products</h2>
<ul className="grid grid-cols-12 gap-6 not-prose [&_svg]:text-brand-600">
{products.map((product) => {
return (
<li key={product.title} className={cn(product.span ?? 'col-span-12 md:col-span-4')}>
<Link href={product.href} passHref>
<GlassPanelWithIconPicker {...product}>
{product.description}
</GlassPanelWithIconPicker>
</Link>
</li>
)
})}
</ul>
{isFeatureEnabled('docs:full_getting_started') && (
<div className="flex flex-col gap-6 border-b py-12 lg:grid lg:grid-cols-12 lg:gap-x-16">
<div className="col-span-4 flex flex-col gap-1 [&_h2]:m-0">
<h2 id="connect-a-framework" className="group scroll-mt-24">
Connect a framework
</h2>
<p className="m-0 p-0 text-sm text-foreground-light">
Start with a framework quickstart and connect your project in minutes.
</p>
</div>

<div className="col-span-8 not-prose">
<FrameworkQuickstarts />
</div>
</div>
)}
<div className="flex flex-col gap-6 border-b py-12 lg:grid lg:grid-cols-12 lg:gap-x-16">
<div className="col-span-4 flex flex-col gap-1 [&_h2]:m-0">
<h2 id="products" className="group scroll-mt-24">
Build your backend
</h2>
<p className="m-0 p-0 text-sm text-foreground-light">
Build with a complete backend platform, from your database to your application logic.
</p>
</div>

<div className="flex flex-col lg:grid grid-cols-12 gap-6 py-12 border-b">
<div className="col-span-4">
<h2 id="postgres-integrations" className="scroll-mt-24 m-0">
Modules
<ul className="col-span-8 grid grid-cols-12 gap-6 not-prose [&_svg]:text-brand-600">
{products.map((product) => {
return (
<li key={product.title} className={cn(product.span ?? 'col-span-12 md:col-span-6')}>
<Link href={product.href} passHref>
<GlassPanelWithIconPicker {...product}>
{product.description}
</GlassPanelWithIconPicker>
</Link>
</li>
)
})}
</ul>
</div>

<div className="flex flex-col gap-6 border-b py-12 lg:grid lg:grid-cols-12 lg:gap-x-16">
<div className="col-span-4 flex flex-col gap-1 [&_h2]:m-0">
<h2 id="postgres-integrations" className="scroll-mt-24">
Extend your database
</h2>
<p className="m-0 p-0 text-sm text-foreground-light">
Extend your database with built-in tools for AI, APIs, scheduled jobs, and queues.
</p>
</div>
<div className="grid col-span-8 grid-cols-12 gap-6 not-prose">
{postgresIntegrations.map((integration) => (
Expand All @@ -261,15 +291,14 @@ const HomePage = () => (
</div>
</div>

<div className="flex flex-col lg:grid grid-cols-12 gap-6 py-12 border-b">
<div className="flex flex-col gap-6 border-b py-12 lg:grid lg:grid-cols-12 lg:gap-x-16">
<div className="col-span-4 flex flex-col gap-1 [&_h2]:m-0 [&_h3]:m-0">
<div className="md:max-w-xs 2xl:max-w-none">
<div className="flex items-center gap-3 mb-3 text-brand-600">
<h2 id="client-libraries" className="group scroll-mt-24">
Client Libraries
</h2>
</div>
</div>
<h2 id="client-libraries" className="group scroll-mt-24">
Use a client library
</h2>
<p className="m-0 p-0 text-sm text-foreground-light">
Use Supabase from the language and framework your application is built with.
</p>
</div>

<div className="grid col-span-8 grid-cols-12 gap-6 not-prose">
Expand All @@ -291,7 +320,7 @@ const HomePage = () => (
</div>
</div>
{isFeatureEnabled('docs:full_getting_started') && (
<div className="flex flex-col lg:grid grid-cols-12 gap-6 py-12 border-b">
<div className="flex flex-col gap-6 border-b py-12 lg:grid lg:grid-cols-12 lg:gap-x-16">
<div className="col-span-4 flex flex-col gap-1 [&_h2]:m-0">
<h2 id="migrate-to-supabase" className="group scroll-mt-24">
Migrate to Supabase
Expand Down Expand Up @@ -322,20 +351,22 @@ const HomePage = () => (
</div>
)}

<div className="flex flex-col gap-6 py-12 border-b">
<div className="col-span-4 flex flex-col gap-1">
<h2 id="additional-resources" className="group scroll-mt-24 m-0">
Additional resources
<div className="flex flex-col gap-6 border-b py-12 lg:grid lg:grid-cols-12 lg:gap-x-16">
<div className="col-span-4 flex flex-col gap-1 [&_h2]:m-0">
<h2 id="additional-resources" className="group scroll-mt-24">
Explore more
</h2>
<p className="m-0 p-0 text-sm text-foreground-light">
Explore the tools, integrations, and guides that help you get more from Supabase.
</p>
</div>

<ul className="grid grid-cols-12 gap-6 not-prose">
<ul className="col-span-8 grid grid-cols-12 gap-6 not-prose">
{additionalResources.map((resource) => {
return (
<li key={resource.title} className="col-span-12 md:col-span-6 lg:col-span-3">
<li key={resource.title} className="col-span-12 md:col-span-6">
<Link
href={resource.href}
className="col-span-12 md:col-span-6 lg:col-span-3"
passHref
target={resource.external ? '_blank' : undefined}
>
Expand All @@ -349,12 +380,12 @@ const HomePage = () => (
</ul>
</div>
{isFeatureEnabled('docs:full_getting_started') && (
<div className="flex flex-col lg:grid grid-cols-12 gap-6 py-12">
<div className="flex flex-col gap-6 py-12 lg:grid lg:grid-cols-12 lg:gap-x-16">
<div className="col-span-4 flex flex-col gap-1">
<div className="md:max-w-xs 2xl:max-w-none">
<div className="flex items-center gap-3 mb-3 text-brand-600">
<h2 id="self-hosting" className="group scroll-mt-24 m-0">
Self-Hosting
Self-host Supabase
</h2>
</div>
<p className="text-foreground-light text-sm m-0 p-0">
Expand Down
6 changes: 3 additions & 3 deletions apps/docs/components/DocsCoverLogo.tsx
Original file line number Diff line number Diff line change
@@ -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 },
Expand All @@ -24,7 +24,7 @@ const DocsCoverLogo = (props: PropsWithChildren) => {
}

return (
<div className="w-[60px] md:w-[150px] [&_svg]" {...props}>
<div className={className} {...props}>
<LazyMotion features={domAnimation}>
<m.svg
width="100%"
Expand Down
9 changes: 9 additions & 0 deletions apps/docs/components/HomePageCover.constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const setupCommand = {
installCli: 'npm install -g supabase',
installPlugin: 'npx plugins add supabase-community/supabase-plugin',
initialize: 'supabase init',
} as const

export const setupCommands = [setupCommand.installCli, setupCommand.installPlugin].join('\n')

export const 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.`
Loading
Loading