mirror of
https://github.com/supabase/supabase.git
synced 2026-06-18 05:33:50 +08:00
## Problem Our `<Button>` component breaks the default `button` contract by redefining the `type` prop to set its variant (`primary`, `default`, etc) instead of the button type (`submit`, `button`, etc). This is confusing and forces to write more code when using it with shadcn components that expect/inject the standard button props. ## Solution - rename the `type` prop to `variant` - rename the `htmlType` prop to `type` - propagate the changes where necessary - format code ## How to test As this is just prop renaming, if it builds it's ok --------- Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>
411 lines
16 KiB
TypeScript
411 lines
16 KiB
TypeScript
// Import Swiper styles
|
||
import 'swiper/css'
|
||
|
||
import { ArrowUpRight, X } from 'lucide-react'
|
||
import { NextSeo } from 'next-seo'
|
||
import dynamic from 'next/dynamic'
|
||
import Head from 'next/head'
|
||
import NextImage from 'next/image'
|
||
import Link from 'next/link'
|
||
import { useRouter } from 'next/router'
|
||
import { useState } from 'react'
|
||
import { PRODUCT_NAMES } from 'shared-data/products'
|
||
import { Swiper, SwiperSlide } from 'swiper/react'
|
||
import { Badge, Button, Tabs } from 'ui'
|
||
import { Image } from 'ui-patterns/Image'
|
||
import { TweetCard } from 'ui-patterns/TweetCard'
|
||
|
||
import ProductsNav from '@/components/Products/ProductsNav'
|
||
import ProductHeader from '@/components/Sections/ProductHeader'
|
||
import MainProducts from '@/data/MainProducts'
|
||
import ApiExamplesData from '@/data/products/database/api-examples'
|
||
import { ETLVisual } from '@/data/products/database/etl-visual'
|
||
import ExtensionsExamplesData from '@/data/products/database/extensions-examples'
|
||
import HighlightsCards from '@/data/products/database/highlight-cards'
|
||
import SqlViewCarouselData from '@/data/products/database/sql-view-carousel.json'
|
||
import TableViewCarouselData from '@/data/products/database/table-view-carousel.json'
|
||
import { breadcrumbs } from '@/lib/breadcrumbs'
|
||
import { breadcrumbListSchema, serializeJsonLd, softwareApplicationSchema } from '@/lib/json-ld'
|
||
|
||
const NewFeatureCard = dynamic(() => import('~/components/NewFeatureCard'))
|
||
const ImageCarousel = dynamic(() => import('~/components/Carousels/ImageCarousel'))
|
||
const SplitCodeBlockCarousel = dynamic(
|
||
() => import('~/components/Carousels/SplitCodeBlockCarousel')
|
||
)
|
||
const FeatureColumn = dynamic(() => import('~/components/FeatureColumn'))
|
||
const SingleQuote = dynamic(() => import('~/components/Sections/SingleQuote'))
|
||
const DefaultLayout = dynamic(() => import('~/components/Layouts/Default'))
|
||
const SectionContainer = dynamic(() => import('~/components/Layouts/SectionContainer'))
|
||
const ProductIcon = dynamic(() => import('~/components/ProductIcon'))
|
||
const APISection = dynamic(() => import('~/components/Sections/APISection'))
|
||
const GithubExamples = dynamic(() => import('~/components/Sections/GithubExamples'))
|
||
|
||
// When updating page content, also update public/llms/database.txt
|
||
|
||
function Database() {
|
||
// base path for images
|
||
const { basePath } = useRouter()
|
||
|
||
const [dashboardSwiper, setDashboardSwiper] = useState(undefined)
|
||
const [dashboardSwiperActiveIndex, setDashboardSwiperActiveIndex] = useState(0)
|
||
|
||
function handleDashboardSwiperNav(e: number) {
|
||
setDashboardSwiperActiveIndex(e)
|
||
// @ts-ignore
|
||
dashboardSwiper.slideTo(e)
|
||
}
|
||
|
||
const meta_title = 'Database | Open source SQL Database'
|
||
const meta_description =
|
||
'With supabase’s APIs and easy to use dashboard, it makes designing relational databases easy.'
|
||
|
||
return (
|
||
<>
|
||
<NextSeo
|
||
title={meta_title}
|
||
description={meta_description}
|
||
openGraph={{
|
||
title: meta_title,
|
||
description: meta_description,
|
||
url: `https://supabase.com/database`,
|
||
images: [
|
||
{
|
||
url: `https://supabase.com${basePath}/images/product/database/database-og.jpg`,
|
||
},
|
||
],
|
||
}}
|
||
/>
|
||
<Head>
|
||
<script
|
||
type="application/ld+json"
|
||
dangerouslySetInnerHTML={{
|
||
__html: serializeJsonLd(
|
||
softwareApplicationSchema({
|
||
name: 'Supabase Database',
|
||
description: meta_description,
|
||
url: 'https://supabase.com/database',
|
||
image: `https://supabase.com${basePath}/images/product/database/database-og.jpg`,
|
||
})
|
||
),
|
||
}}
|
||
/>
|
||
<script
|
||
type="application/ld+json"
|
||
dangerouslySetInnerHTML={{
|
||
__html: serializeJsonLd(breadcrumbListSchema(breadcrumbs.database)),
|
||
}}
|
||
/>
|
||
</Head>
|
||
<DefaultLayout>
|
||
<ProductsNav activePage={PRODUCT_NAMES.DATABASE} />
|
||
<ProductHeader
|
||
icon={MainProducts['database'].icon}
|
||
title={MainProducts['database'].name}
|
||
h1={[
|
||
<span key={'database-h1'}>
|
||
It’s just Postgres
|
||
<br /> (without the hassle)
|
||
</span>,
|
||
]}
|
||
subheader={[
|
||
'Every Supabase project is a dedicated Postgres database, trusted by millions of developers.',
|
||
"Postgres is one of the world's most scalable databases.",
|
||
]}
|
||
image={[
|
||
<Image
|
||
src={{
|
||
dark: `${basePath}/images/product/database/header--dark-2.png`,
|
||
light: `${basePath}/images/product/database/header--light-2.png`,
|
||
}}
|
||
alt="database header"
|
||
layout="responsive"
|
||
width="1680"
|
||
height="1116"
|
||
/>,
|
||
]}
|
||
documentation_url={'/docs/guides/database'}
|
||
/>
|
||
|
||
<SectionContainer>
|
||
<div className="grid grid-cols-12">
|
||
<div className="col-span-12 mb-10 lg:col-span-3 lg:mb-0">
|
||
<div className="p mb-4 flex items-center space-x-2">
|
||
<ProductIcon icon={MainProducts['database'].icon} />
|
||
<X />
|
||
<div className="flex w-fit items-center">
|
||
<NextImage
|
||
src={`${basePath}/images/product/database/postgresql-icon.svg`}
|
||
width={30}
|
||
height={30}
|
||
alt="Postgres icon"
|
||
/>
|
||
</div>
|
||
</div>
|
||
<h4 className="h4">Just Postgres</h4>
|
||
<p className="p">Every Supabase project is a dedicated Postgres database.</p>
|
||
<p className="p text-sm">
|
||
100% portable. Bring your existing Postgres database, or migrate away at any time.
|
||
</p>
|
||
</div>
|
||
<div className="col-span-12 mb-10 lg:col-span-3 lg:col-start-5 lg:mb-0">
|
||
<div className="p mb-4 flex items-center space-x-2">
|
||
<ProductIcon icon={MainProducts['database'].icon} />
|
||
<X />
|
||
<ProductIcon icon={MainProducts['authentication'].icon} />
|
||
</div>
|
||
|
||
<h4 className="h4">Secure by default</h4>
|
||
<p className="p">Leveraging Postgres's proven Row Level Security.</p>
|
||
<p className="p text-sm">
|
||
Integrated with JWT authentication which controls exactly what your users can
|
||
access.
|
||
</p>
|
||
</div>
|
||
<div className="col-span-12 lg:col-span-3 lg:col-start-9">
|
||
<div className="p mb-4 flex items-center space-x-2">
|
||
<ProductIcon icon={MainProducts['database'].icon} />
|
||
<X />
|
||
<ProductIcon icon={'M13 10V3L4 14h7v7l9-11h-7z'} />
|
||
</div>
|
||
|
||
<h4 className="h4">Realtime enabled</h4>
|
||
<p className="p">Data-change listeners over websockets.</p>
|
||
<p className="p text-sm">
|
||
Subscribe and react to database changes, milliseconds after they happen.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</SectionContainer>
|
||
|
||
<SingleQuote
|
||
id="quote"
|
||
quote={{
|
||
text: 'You can have a really great product, but you need to want to work with the people behind it. With Supabase, we always felt very aligned.',
|
||
author: 'Howard Haynes',
|
||
role: 'CPO at Next Door Lending',
|
||
link: '/customers/next-door-lending',
|
||
logo: (
|
||
<NextImage
|
||
draggable={false}
|
||
src="/images/blog/avatars/howard-haynes.webp"
|
||
alt="Howard Haynes, CPO at Next Door Lending"
|
||
className="w-10 h-10 rounded-full overflow-hidden object-cover"
|
||
width={28}
|
||
height={28}
|
||
/>
|
||
),
|
||
}}
|
||
/>
|
||
|
||
<SectionContainer className="grid lg:grid-cols-2 gap-2 lg:gap-4">
|
||
<NewFeatureCard {...HighlightsCards.branching} />
|
||
<NewFeatureCard {...HighlightsCards.readReplicas} />
|
||
</SectionContainer>
|
||
|
||
{/* <SectionContainer>÷ */}
|
||
<SectionContainer className="text-center md:pb-0 lg:pb-0">
|
||
<div className="grid grid-cols-12">
|
||
<div className="col-span-12 lg:col-span-8 lg:col-start-3">
|
||
<h2 className="h3">Easy to use dashboard</h2>
|
||
|
||
<p className="p">
|
||
The simplicity of a Table Editor, or the power of a SQL editor. Your choice.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</SectionContainer>
|
||
<div className="grid">
|
||
<div className={'dashboard-tabs sbui-tabs--underline-alt'}>
|
||
<Tabs
|
||
size="xlarge"
|
||
activeId={dashboardSwiperActiveIndex.toString()}
|
||
onChange={(e: string) => handleDashboardSwiperNav(Number(e))}
|
||
type="underlined"
|
||
tabBarStyle={{
|
||
marginBottom: 0,
|
||
// borderBottom: '1px solid #dedede',
|
||
}}
|
||
// block
|
||
>
|
||
<Tabs.Panel id="0" label="Table editor">
|
||
<span></span>
|
||
</Tabs.Panel>
|
||
<Tabs.Panel id="1" label="SQL editor">
|
||
<span></span>
|
||
</Tabs.Panel>
|
||
</Tabs>
|
||
</div>
|
||
</div>
|
||
|
||
<Swiper
|
||
// @ts-ignore
|
||
onSwiper={setDashboardSwiper}
|
||
style={{ overflow: 'hidden' }}
|
||
initialSlide={0}
|
||
spaceBetween={0}
|
||
slidesPerView={1}
|
||
speed={300}
|
||
allowTouchMove={false}
|
||
>
|
||
<div className="grid grid-cols-12">
|
||
<SwiperSlide key={0}>
|
||
<SectionContainer className="pt-16 pb-0">
|
||
<ImageCarousel
|
||
content={TableViewCarouselData}
|
||
footer={[
|
||
<TweetCard
|
||
handle="@Elsolo244"
|
||
key="@Elsolo244"
|
||
img_url={`${basePath}/images/twitter-profiles/v6citnk33y2wpeyzrq05_400x400.jpeg`}
|
||
quote="Where has @supabase been all my life? 😍"
|
||
/>,
|
||
]}
|
||
/>
|
||
</SectionContainer>
|
||
</SwiperSlide>
|
||
<SwiperSlide key={1}>
|
||
<SectionContainer className="pt-16 pb-0">
|
||
<ImageCarousel
|
||
content={SqlViewCarouselData}
|
||
footer={[
|
||
<TweetCard
|
||
handle="@jim_bisenius"
|
||
key="@jim_bisenius"
|
||
img_url={`${basePath}/images/twitter-profiles/rLgwUZSB_400x400.jpg`}
|
||
quote="@MongoDB or @MySQL?!?! Please, let me introduce you to @supabase and the wonderful world of @Postgres before it's too late!!"
|
||
/>,
|
||
]}
|
||
/>
|
||
</SectionContainer>
|
||
</SwiperSlide>
|
||
</div>
|
||
</Swiper>
|
||
|
||
<SectionContainer>
|
||
<div className="grid grid-cols-12 lg:gap-16">
|
||
<div className="col-span-12 mb-8 lg:col-span-6 xl:col-span-5">
|
||
<h2 className="h2">Supabase ETL</h2>
|
||
<p className="p text-lg">Stream your Postgres data to external systems.</p>
|
||
<p className="p">
|
||
Automatically replicate your database changes to external data warehouses and
|
||
analytics platforms in real-time, without pipelines.
|
||
</p>
|
||
|
||
<div className="my-8">
|
||
<FeatureColumn
|
||
title="Offload analytics"
|
||
text="Keep Postgres focused on transactional workloads."
|
||
/>
|
||
<FeatureColumn
|
||
title="Point and stream setup"
|
||
text="Configure in the Supabase Dashboard."
|
||
/>
|
||
<FeatureColumn title="Open table formats" text="For long term flexibility." />
|
||
</div>
|
||
|
||
<div className="mt-4 flex gap-2">
|
||
<Button asChild size="small" variant="default" icon={<ArrowUpRight />}>
|
||
<Link href="/docs/guides/database/replication">Read the docs</Link>
|
||
</Button>
|
||
<Button asChild size="small" variant="default" icon={<ArrowUpRight />}>
|
||
<Link href="/blog/supabase-etl">Read the blog post</Link>
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
<div className="col-span-12 lg:col-span-6 lg:col-start-7">
|
||
{/* TODO: Add ETL illustration */}
|
||
<ETLVisual className="w-full" />
|
||
</div>
|
||
</div>
|
||
</SectionContainer>
|
||
|
||
<SectionContainer className="-mb-48">
|
||
<APISection
|
||
// @ts-ignore
|
||
content={ApiExamplesData}
|
||
title="Never write an API again"
|
||
text={[
|
||
<p key={0}>
|
||
We introspect your database and provide instant APIs. Focus on building your
|
||
product, while Supabase handles the CRUD.
|
||
</p>,
|
||
]}
|
||
footer={[
|
||
<div className="grid grid-cols-12" key={0}>
|
||
<div className="col-span-12 mt-0 flex flex-col 2xl:flex-row lg:col-span-6 xl:col-span-12 xl:mb-8 gap-1 xl:gap-2 xl:items-center">
|
||
<p className="text-foreground-light m-0">Available libraries:</p>
|
||
<div className="flex gap-1 xl:mb-0.5">
|
||
<Link href="/docs/reference/javascript/introduction" target="_blank">
|
||
<Badge>Javascript</Badge>
|
||
</Link>
|
||
<Link href="/docs/reference/dart/introduction" target="_blank">
|
||
<Badge>Flutter</Badge>
|
||
</Link>
|
||
<Link href="/docs/reference/python/introduction" target="_blank">
|
||
<Badge>Python</Badge>
|
||
</Link>
|
||
<Link href="/docs/reference/csharp/introduction" target="_blank">
|
||
<Badge>C#</Badge>
|
||
</Link>
|
||
<Link href="/docs/reference/kotlin/introduction" target="_blank">
|
||
<Badge>Kotlin</Badge>
|
||
</Link>
|
||
<Link href="/docs/reference/swift/introduction" target="_blank">
|
||
<Badge>Swift</Badge>
|
||
</Link>
|
||
</div>
|
||
</div>
|
||
</div>,
|
||
]}
|
||
documentation_link={'/docs/guides/database'}
|
||
/>
|
||
</SectionContainer>
|
||
|
||
<div className="relative">
|
||
<div className="section--masked">
|
||
<div className="section--bg-masked">
|
||
<div className="section--bg border-t border-b border-control"></div>
|
||
</div>
|
||
<div className="section-container pt-12 pb-0">
|
||
<div className="overflow-x-hidden">
|
||
<SectionContainer className="mb-0 pb-8 lg:pt-32">
|
||
<GithubExamples />
|
||
</SectionContainer>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<SectionContainer>
|
||
<div className="grid grid-cols-12 lg:gap-16">
|
||
<div className="col-span-12 mb-8 lg:col-span-6 xl:col-span-5">
|
||
<h2 className="h3">Extend your database</h2>
|
||
|
||
<p className="p">Supabase works natively with Postgres extensions.</p>
|
||
<p className="p">
|
||
Choose from a huge collection of Postgres extensions, enabled with a single click.
|
||
</p>
|
||
|
||
<FeatureColumn
|
||
title="40+ preinstalled extensions"
|
||
text="We only show a few of the extensions supported by Supabase here, but we preinstall many more that you can use right away."
|
||
/>
|
||
<Button asChild size="small" variant="default" icon={<ArrowUpRight />}>
|
||
<Link href="/docs/guides/database">Explore documentation</Link>
|
||
</Button>
|
||
</div>
|
||
<div className="col-span-12 mt-8 lg:col-span-6 lg:col-start-7 lg:mt-0">
|
||
<SplitCodeBlockCarousel
|
||
// @ts-ignore
|
||
content={ExtensionsExamplesData}
|
||
/>
|
||
</div>
|
||
</div>
|
||
</SectionContainer>
|
||
</DefaultLayout>
|
||
</>
|
||
)
|
||
}
|
||
|
||
export default Database
|