mirror of
https://github.com/supabase/supabase.git
synced 2026-10-19 08:09:11 +03:00
Merge branch 'master' into chore/cleanup
This commit is contained in:
commit
74ed21ed47
290 files changed
+6056
-2785
No files matched your search
@@ -3,4 +3,5 @@
|
||||
|
||||
/apps/studio/ @supabase/Dashboard
|
||||
/apps/www/ @supabase/Website
|
||||
/apps/www/_blog
|
||||
/docker/ @supabase/cli
|
||||
@@ -0,0 +1,23 @@
|
||||
name: reviewdog
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- '.vale.ini'
|
||||
- 'vale/**'
|
||||
- 'apps/docs/content/**'
|
||||
|
||||
jobs:
|
||||
vale:
|
||||
name: runner / vale
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
sparse-checkout: |
|
||||
.vale.ini
|
||||
vale
|
||||
apps/docs/content
|
||||
- uses: errata-ai/vale-action@reviewdog
|
||||
with:
|
||||
files: apps/docs/content
|
||||
fail_on_error: true
|
||||
@@ -39,6 +39,8 @@ jobs:
|
||||
run: npx playwright install --with-deps
|
||||
- name: Run Playwright tests
|
||||
run: npm run test:playwright
|
||||
# mark the action as succeeded even if the tests failed. This is temporarily until we make the tests more stable.
|
||||
continue-on-error: true
|
||||
# - uses: actions/upload-artifact@v3
|
||||
# if: always()
|
||||
# with:
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
StylesPath = './vale/styles'
|
||||
MinAlertLevel = 'suggestion'
|
||||
|
||||
Vocab = Supabase
|
||||
|
||||
[formats]
|
||||
mdx = md
|
||||
|
||||
[*]
|
||||
BasedOnStyles = Vale, Custom
|
||||
BlockIgnores = (?s) *(<StepHikeCompact>.*?</StepHikeCompact>)
|
||||
TokenIgnores = (href=".*?")
|
||||
@@ -21,7 +21,7 @@
|
||||
"dayjs": "^1.11.10",
|
||||
"eslint-config-next": "^14.1.0",
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-react": "^0.292.0",
|
||||
"lucide-react": "^0.338.0",
|
||||
"next": "^14.0.3",
|
||||
"openai": "^4.17.0",
|
||||
"react": "^18.2.0",
|
||||
|
||||
+13
-41
@@ -70,7 +70,7 @@ They shouldn't include:
|
||||
|
||||
## Repo organization
|
||||
|
||||
Most docs pages are contained in the `apps/docs/pages` directory. Some docs sections are federated from other repositories, for example [`pg_graphql`](https://github.com/supabase/pg_graphql/tree/master/docs). Reference docs are generated from spec files in the `spec` directory.
|
||||
Most docs pages are contained in the `apps/docs/content` directory. Some docs sections are federated from other repositories, for example [`pg_graphql`](https://github.com/supabase/pg_graphql/tree/master/docs). Reference docs are generated from spec files in the `spec` directory.
|
||||
|
||||
You can usually identify a federated or reference doc because it uses a Next.js dynamic route (for example, `[[...slug]].tsx`). Look for the spec file import or the repo definition to find the content location.
|
||||
|
||||
@@ -98,43 +98,16 @@ The Supabase docs use [MDX](https://mdxjs.com/). Guides are written in unstructu
|
||||
|
||||
Adding a new guide requires:
|
||||
|
||||
- A layout
|
||||
- Metadata
|
||||
- A page export
|
||||
- YAML frontmatter
|
||||
- A navigation entry (in a separate file)
|
||||
|
||||
```js
|
||||
// required import
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
Frontmatter looks like this. `title` is mandatory. There are also optional properties that you can use to control the page display, including `subtitle`, `tocVideo`, and `hideToc`.
|
||||
|
||||
|
||||
/*
|
||||
* required metadata fields
|
||||
* title: required - page title
|
||||
* description: required - page description
|
||||
*
|
||||
* optional metadata fields
|
||||
* id: optional - not currently being used
|
||||
* subtitle: optional - displayed below the title
|
||||
* sidebar_label: optional - if you want the sidebar text to be different from the title
|
||||
* hide_table_of_contents: optional - hides the table of contents on the right side
|
||||
* tocVideo: optional - a YouTube slug, displays the video above the table of contents
|
||||
*/
|
||||
export const meta = {
|
||||
id: 'nextjs-server-components',
|
||||
title: 'Supabase Auth with Next.js Server Components',
|
||||
description:
|
||||
'Authentication helpers for creating an authenticated Supabase client in Next.js 13 app directory Server Components.',
|
||||
sidebar_label: 'Next.js Server Components',
|
||||
}
|
||||
|
||||
// content
|
||||
You can use **Markdown syntax**.
|
||||
|
||||
// required export
|
||||
export const Page = ({ children }) => <Layout meta={meta} children={children} />
|
||||
|
||||
export default Page
|
||||
```yaml
|
||||
---
|
||||
title: How to connect to Supabase
|
||||
hideToc: true
|
||||
---
|
||||
```
|
||||
|
||||
The navigation is defined in [`NavigationMenu.constants.ts`](https://github.com/supabase/supabase/blob/master/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts).
|
||||
@@ -305,13 +278,12 @@ The `queryGroup` param is optional. It lets you link directly to a tab by using
|
||||
|
||||
Include videos as TOC (Table of Contents) videos rather than putting them in the main text.
|
||||
|
||||
You can define a TOC video in the page metadata:
|
||||
You can define a TOC video in the page frontmatter:
|
||||
|
||||
```js
|
||||
export const meta = {
|
||||
...
|
||||
tocVideo: 'rzglqRdZUQE',
|
||||
}
|
||||
```yaml
|
||||
---
|
||||
tocVideo: 'rzglqRdZUQE',
|
||||
---
|
||||
```
|
||||
|
||||
## Styling, formatting, and grammar
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
import Link from 'next/link'
|
||||
import { memo } from 'react'
|
||||
|
||||
import { Button, IconExternalLink, cn } from 'ui'
|
||||
|
||||
export const IPv4DeprecationBanner = memo(() => {
|
||||
return (
|
||||
<div
|
||||
role="region"
|
||||
aria-label="Deprecation notice"
|
||||
className="flex items-center justify-center gap-x-4 bg-surface-100 p-2 transition text-foreground box-border border-b border-default"
|
||||
>
|
||||
<p className="text-sm">
|
||||
Prepare for the PgBouncer and IPv4 deprecations on 26th January 2024{' '}
|
||||
<Link
|
||||
href="https://github.com/orgs/supabase/discussions/17817"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className={cn(
|
||||
'sm:hidden',
|
||||
'inline-flex items-center justify-center px-2.5 py-1',
|
||||
'border border-transparent rounded-md',
|
||||
'text-xs text-brand-600 hover:bg-brand-400',
|
||||
'ease-out duration-200 transition-all'
|
||||
)}
|
||||
aria-hidden="true"
|
||||
>
|
||||
Learn more
|
||||
</Link>
|
||||
</p>
|
||||
<div className="max-sm:sr-only sm:flex items-center gap-x-1">
|
||||
<Button asChild type="link" iconRight={<IconExternalLink />}>
|
||||
<a
|
||||
href="https://github.com/orgs/supabase/discussions/17817"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
Learn more
|
||||
</a>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
IPv4DeprecationBanner.displayName = 'IPv4DeprecationBanner'
|
||||
@@ -1,13 +1,45 @@
|
||||
import { useRouter } from 'next/router'
|
||||
import { memo, useEffect } from 'react'
|
||||
import { menuState, useMenuLevelId } from '~/hooks/useMenuState'
|
||||
import { memo } from 'react'
|
||||
import NavigationMenuHome from './HomeMenu'
|
||||
import NavigationMenuGuideList from './NavigationMenuGuideList'
|
||||
import NavigationMenuRefList from './NavigationMenuRefList'
|
||||
|
||||
enum MenuId {
|
||||
Home = 'home',
|
||||
GettingStarted = 'gettingstarted',
|
||||
Database = 'database',
|
||||
Api = 'api',
|
||||
Graphql = 'graphql',
|
||||
Auth = 'auth',
|
||||
Functions = 'functions',
|
||||
Realtime = 'realtime',
|
||||
Storage = 'storage',
|
||||
Ai = 'ai',
|
||||
Platform = 'platform',
|
||||
Resources = 'resources',
|
||||
SelfHosting = 'self_hosting',
|
||||
Integrations = 'integrations',
|
||||
Cli = 'supabase_cli',
|
||||
RefJavaScriptV1 = 'reference_javascript_v1',
|
||||
RefJavaScriptV2 = 'reference_javascript_v2',
|
||||
RefDartV1 = 'reference_dart_v1',
|
||||
RefDartV2 = 'reference_dart_v2',
|
||||
RefCSharpV0 = 'reference_csharp_v0',
|
||||
RefPythonV2 = 'reference_python_v2',
|
||||
RefSwiftV1 = 'reference_swift_v1',
|
||||
RefSwiftV2 = 'reference_swift_v2',
|
||||
RefKotlinV1 = 'reference_kotlin_v1',
|
||||
RefKotlinV2 = 'reference_kotlin_v2',
|
||||
RefCli = 'reference_cli',
|
||||
RefApi = 'reference_api',
|
||||
SelfHostingAuth = 'reference_self_hosting_auth',
|
||||
SelfHostingStorage = 'reference_self_hosting_storage',
|
||||
SelfHostingRealtime = 'reference_self_hosting_realtime',
|
||||
SelfHostingAnalytics = 'reference_self_hosting_analytics',
|
||||
SelfHostingFunctions = 'reference_self_hosting_functions',
|
||||
}
|
||||
|
||||
interface BaseMenu {
|
||||
id: string
|
||||
path: string
|
||||
id: MenuId
|
||||
type: string
|
||||
}
|
||||
|
||||
@@ -21,6 +53,7 @@ interface GuideMenu extends BaseMenu {
|
||||
|
||||
interface ReferenceMenu extends BaseMenu {
|
||||
type: 'reference'
|
||||
path: string
|
||||
commonSectionsFile: string
|
||||
specFile?: string
|
||||
}
|
||||
@@ -29,211 +62,181 @@ type Menu = HomeMenu | GuideMenu | ReferenceMenu
|
||||
|
||||
const menus: Menu[] = [
|
||||
{
|
||||
id: 'home',
|
||||
path: '/',
|
||||
id: MenuId.Home,
|
||||
type: 'home',
|
||||
},
|
||||
{
|
||||
id: 'gettingstarted',
|
||||
path: '/guides/getting-started',
|
||||
id: MenuId.GettingStarted,
|
||||
type: 'guide',
|
||||
},
|
||||
{
|
||||
id: 'database',
|
||||
path: '/guides/database',
|
||||
id: MenuId.Database,
|
||||
type: 'guide',
|
||||
},
|
||||
{
|
||||
id: 'api',
|
||||
path: '/guides/api',
|
||||
id: MenuId.Api,
|
||||
type: 'guide',
|
||||
},
|
||||
{
|
||||
id: 'graphql',
|
||||
path: '/guides/graphql',
|
||||
id: MenuId.Graphql,
|
||||
type: 'guide',
|
||||
},
|
||||
{
|
||||
id: 'auth',
|
||||
path: '/guides/auth',
|
||||
id: MenuId.Auth,
|
||||
type: 'guide',
|
||||
},
|
||||
{
|
||||
id: 'auth',
|
||||
path: '/learn/auth-deep-dive',
|
||||
id: MenuId.Functions,
|
||||
type: 'guide',
|
||||
},
|
||||
{
|
||||
id: 'functions',
|
||||
path: '/guides/functions',
|
||||
id: MenuId.Realtime,
|
||||
type: 'guide',
|
||||
},
|
||||
{
|
||||
id: 'realtime',
|
||||
path: '/guides/realtime',
|
||||
id: MenuId.Storage,
|
||||
type: 'guide',
|
||||
},
|
||||
{
|
||||
id: 'storage',
|
||||
path: '/guides/storage',
|
||||
id: MenuId.Ai,
|
||||
type: 'guide',
|
||||
},
|
||||
{
|
||||
id: 'ai',
|
||||
path: '/guides/ai',
|
||||
id: MenuId.Platform,
|
||||
type: 'guide',
|
||||
},
|
||||
{
|
||||
id: 'platform',
|
||||
path: '/guides/platform',
|
||||
id: MenuId.Resources,
|
||||
type: 'guide',
|
||||
},
|
||||
{
|
||||
id: 'resources',
|
||||
path: '/guides/resources',
|
||||
id: MenuId.SelfHosting,
|
||||
type: 'guide',
|
||||
},
|
||||
{
|
||||
id: 'self_hosting',
|
||||
path: '/guides/self-hosting',
|
||||
id: MenuId.Integrations,
|
||||
type: 'guide',
|
||||
},
|
||||
{
|
||||
id: 'integrations',
|
||||
path: '/guides/integrations',
|
||||
id: MenuId.Cli,
|
||||
type: 'guide',
|
||||
},
|
||||
{
|
||||
id: 'supabase_cli',
|
||||
// TODO: Add path '/guides/cli/config'
|
||||
path: '/guides/cli',
|
||||
type: 'guide',
|
||||
},
|
||||
{
|
||||
id: 'reference_javascript_v1',
|
||||
path: '/reference/javascript/v1',
|
||||
id: MenuId.RefJavaScriptV1,
|
||||
commonSectionsFile: 'common-client-libs-sections.json',
|
||||
specFile: 'supabase_js_v1.yml',
|
||||
type: 'reference',
|
||||
path: '/reference/javascript/v1',
|
||||
},
|
||||
{
|
||||
id: 'reference_javascript_v2',
|
||||
path: '/reference/javascript',
|
||||
id: MenuId.RefJavaScriptV2,
|
||||
commonSectionsFile: 'common-client-libs-sections.json',
|
||||
specFile: 'supabase_js_v2.yml',
|
||||
type: 'reference',
|
||||
path: '/reference/javascript',
|
||||
},
|
||||
{
|
||||
id: 'reference_dart_v1',
|
||||
path: '/reference/dart/v1',
|
||||
id: MenuId.RefDartV1,
|
||||
commonSectionsFile: 'common-client-libs-sections.json',
|
||||
specFile: 'supabase_dart_v1.yml',
|
||||
type: 'reference',
|
||||
path: '/reference/dart/v1',
|
||||
},
|
||||
{
|
||||
id: 'reference_dart_v2',
|
||||
path: '/reference/dart',
|
||||
id: MenuId.RefDartV2,
|
||||
commonSectionsFile: 'common-client-libs-sections.json',
|
||||
specFile: 'supabase_dart_v2.yml',
|
||||
type: 'reference',
|
||||
path: '/reference/dart',
|
||||
},
|
||||
{
|
||||
id: 'reference_csharp_v0',
|
||||
path: '/reference/csharp',
|
||||
id: MenuId.RefCSharpV0,
|
||||
commonSectionsFile: 'common-client-libs-sections.json',
|
||||
specFile: 'supabase_csharp_v0.yml',
|
||||
type: 'reference',
|
||||
path: '/reference/csharp',
|
||||
},
|
||||
{
|
||||
id: 'reference_python_v2',
|
||||
path: '/reference/python',
|
||||
id: MenuId.RefPythonV2,
|
||||
commonSectionsFile: 'common-client-libs-sections.json',
|
||||
specFile: 'supabase_py_v2.yml',
|
||||
type: 'reference',
|
||||
path: '/reference/python',
|
||||
},
|
||||
{
|
||||
id: 'reference_swift_v1',
|
||||
path: '/reference/swift',
|
||||
id: MenuId.RefSwiftV1,
|
||||
commonSectionsFile: 'common-client-libs-sections.json',
|
||||
specFile: 'supabase_swift_v1.yml',
|
||||
type: 'reference',
|
||||
path: '/reference/swift',
|
||||
},
|
||||
{
|
||||
id: 'reference_swift_v2',
|
||||
path: '/reference/swift',
|
||||
id: MenuId.RefSwiftV2,
|
||||
commonSectionsFile: 'common-client-libs-sections.json',
|
||||
specFile: 'supabase_swift_v2.yml',
|
||||
type: 'reference',
|
||||
path: '/reference/swift',
|
||||
},
|
||||
{
|
||||
id: 'reference_kotlin_v1',
|
||||
path: '/reference/kotlin/v1',
|
||||
id: MenuId.RefKotlinV1,
|
||||
commonSectionsFile: 'common-client-libs-sections.json',
|
||||
specFile: 'supabase_kt_v1.yml',
|
||||
type: 'reference',
|
||||
path: '/reference/kotlin/v1',
|
||||
},
|
||||
{
|
||||
id: 'reference_kotlin_v2',
|
||||
path: '/reference/kotlin',
|
||||
id: MenuId.RefKotlinV2,
|
||||
commonSectionsFile: 'common-client-libs-sections.json',
|
||||
specFile: 'supabase_kt_v2.yml',
|
||||
type: 'reference',
|
||||
path: '/reference/kotlin',
|
||||
},
|
||||
{
|
||||
id: 'reference_cli',
|
||||
path: '/reference/cli',
|
||||
id: MenuId.RefCli,
|
||||
commonSectionsFile: 'common-cli-sections.json',
|
||||
type: 'reference',
|
||||
path: '/reference/cli',
|
||||
},
|
||||
{
|
||||
id: 'reference_api',
|
||||
path: '/reference/api',
|
||||
id: MenuId.RefApi,
|
||||
commonSectionsFile: 'common-api-sections.json',
|
||||
type: 'reference',
|
||||
path: '/reference/api',
|
||||
},
|
||||
{
|
||||
id: 'reference_self_hosting_auth',
|
||||
path: '/reference/self-hosting-auth',
|
||||
id: MenuId.SelfHostingAuth,
|
||||
commonSectionsFile: 'common-self-hosting-auth-sections.json',
|
||||
type: 'reference',
|
||||
path: '/reference/self-hosting-auth',
|
||||
},
|
||||
{
|
||||
id: 'reference_self_hosting_storage',
|
||||
path: '/reference/self-hosting-storage',
|
||||
id: MenuId.SelfHostingStorage,
|
||||
commonSectionsFile: 'common-self-hosting-storage-sections.json',
|
||||
type: 'reference',
|
||||
path: '/reference/self-hosting-storage',
|
||||
},
|
||||
{
|
||||
id: 'reference_self_hosting_realtime',
|
||||
path: '/reference/self-hosting-realtime',
|
||||
id: MenuId.SelfHostingRealtime,
|
||||
commonSectionsFile: 'common-self-hosting-realtime-sections.json',
|
||||
type: 'reference',
|
||||
path: '/reference/self-hosting-realtime',
|
||||
},
|
||||
{
|
||||
id: 'reference_self_hosting_analytics',
|
||||
path: '/reference/self-hosting-analytics',
|
||||
id: MenuId.SelfHostingAnalytics,
|
||||
commonSectionsFile: 'common-self-hosting-analytics-sections.json',
|
||||
type: 'reference',
|
||||
path: '/reference/self-hosting-analytics',
|
||||
},
|
||||
{
|
||||
id: 'reference_self_hosting_functions',
|
||||
path: '/reference/self-hosting-functions',
|
||||
id: MenuId.SelfHostingFunctions,
|
||||
commonSectionsFile: 'common-self-hosting-functions-sections.json',
|
||||
type: 'reference',
|
||||
path: '/reference/self-hosting-functions',
|
||||
},
|
||||
]
|
||||
|
||||
function getMenuById(id: string) {
|
||||
return menus.find((menu) => menu.id === id)
|
||||
}
|
||||
|
||||
function getMenuByUrl(basePath: string, url: string) {
|
||||
// If multiple matches, choose the menu with the longest path
|
||||
const [menu] = menus
|
||||
.filter(({ path }) => url.startsWith(`${basePath}${path}`))
|
||||
.sort((a, b) => b.path.length - a.path.length)
|
||||
|
||||
return menu
|
||||
function getMenuById(id: MenuId) {
|
||||
return menus.find((menu) => menu.id === id) ?? menus.find((menu) => menu.id === MenuId.Home)
|
||||
}
|
||||
|
||||
function getMenuElement(menu: Menu) {
|
||||
@@ -257,29 +260,12 @@ function getMenuElement(menu: Menu) {
|
||||
}
|
||||
}
|
||||
|
||||
const NavigationMenu = () => {
|
||||
const router = useRouter()
|
||||
|
||||
useEffect(() => {
|
||||
function handleRouteChange(url: string) {
|
||||
const menu = getMenuByUrl(router.basePath, url)
|
||||
if (menu) {
|
||||
menuState.setMenuLevelId(menu.id)
|
||||
}
|
||||
}
|
||||
|
||||
handleRouteChange(router.basePath + router.asPath)
|
||||
// Listen for page changes after a navigation or when the query changes
|
||||
router.events.on('routeChangeComplete', handleRouteChange)
|
||||
return () => {
|
||||
router.events.off('routeChangeComplete', handleRouteChange)
|
||||
}
|
||||
}, [router.asPath, router.basePath, router.events])
|
||||
|
||||
const level = useMenuLevelId()
|
||||
const NavigationMenu = ({ menuId }: { menuId: MenuId }) => {
|
||||
const level = menuId
|
||||
const menu = getMenuById(level)
|
||||
|
||||
return getMenuElement(menu)
|
||||
}
|
||||
|
||||
export { MenuId }
|
||||
export default memo(NavigationMenu)
|
||||
@@ -2,6 +2,7 @@ import Head from 'next/head'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
import { type MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import RefEducationSection from '~/components/reference/RefEducationSection'
|
||||
import RefFunctionSection from '~/components/reference/RefFunctionSection'
|
||||
|
||||
@@ -10,6 +11,7 @@ import ApiOperationSection from './ApiOperationSection'
|
||||
import CliCommandSection from './CLICommandSection'
|
||||
import OldVersionAlert from './OldVersionAlert'
|
||||
import { IAPISpec, ICommonSection, IRefStaticDoc, ISpec, TypeSpec } from './Reference.types'
|
||||
import { MainSkeleton } from '~/layouts/MainSkeleton'
|
||||
|
||||
interface RefSectionHandlerProps {
|
||||
sections: ICommonSection[]
|
||||
@@ -18,6 +20,7 @@ interface RefSectionHandlerProps {
|
||||
pageProps: { docs: IRefStaticDoc[] }
|
||||
type: 'client-lib' | 'cli' | 'api'
|
||||
isOldVersion?: boolean
|
||||
menuId: MenuId
|
||||
}
|
||||
|
||||
const RefSectionHandler = (props: RefSectionHandlerProps) => {
|
||||
@@ -75,53 +78,55 @@ const RefSectionHandler = (props: RefSectionHandlerProps) => {
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="canonical" href={`https://supabase.com${router.basePath}${path}`} />
|
||||
</Head>
|
||||
{props.isOldVersion && <OldVersionAlert sections={props.sections} />}
|
||||
<RefSubLayout>
|
||||
{props.sections.map((section, i) => {
|
||||
const sectionType = section.type
|
||||
switch (sectionType) {
|
||||
case 'markdown':
|
||||
const markdownData = props.pageProps.docs.find((doc) => doc.id === section.id)
|
||||
<MainSkeleton menuId={props.menuId}>
|
||||
{props.isOldVersion && <OldVersionAlert sections={props.sections} />}
|
||||
<RefSubLayout>
|
||||
{props.sections.map((section, i) => {
|
||||
const sectionType = section.type
|
||||
switch (sectionType) {
|
||||
case 'markdown':
|
||||
const markdownData = props.pageProps.docs.find((doc) => doc.id === section.id)
|
||||
|
||||
return (
|
||||
<RefEducationSection
|
||||
key={section.id + i}
|
||||
item={section}
|
||||
markdownContent={markdownData}
|
||||
/>
|
||||
)
|
||||
case 'function':
|
||||
return (
|
||||
<RefFunctionSection
|
||||
key={section.id + i}
|
||||
funcData={section}
|
||||
commonFuncData={section}
|
||||
spec={props.spec}
|
||||
typeSpec={props.typeSpec}
|
||||
/>
|
||||
)
|
||||
case 'cli-command':
|
||||
return (
|
||||
<CliCommandSection
|
||||
key={section.id + i}
|
||||
funcData={section}
|
||||
commonFuncData={section}
|
||||
/>
|
||||
)
|
||||
case 'operation':
|
||||
return (
|
||||
<ApiOperationSection
|
||||
key={section.id + i}
|
||||
funcData={section}
|
||||
commonFuncData={section}
|
||||
spec={props.spec}
|
||||
/>
|
||||
)
|
||||
default:
|
||||
throw new Error(`Unknown common section type '${sectionType}'`)
|
||||
}
|
||||
})}
|
||||
</RefSubLayout>
|
||||
return (
|
||||
<RefEducationSection
|
||||
key={section.id + i}
|
||||
item={section}
|
||||
markdownContent={markdownData}
|
||||
/>
|
||||
)
|
||||
case 'function':
|
||||
return (
|
||||
<RefFunctionSection
|
||||
key={section.id + i}
|
||||
funcData={section}
|
||||
commonFuncData={section}
|
||||
spec={props.spec}
|
||||
typeSpec={props.typeSpec}
|
||||
/>
|
||||
)
|
||||
case 'cli-command':
|
||||
return (
|
||||
<CliCommandSection
|
||||
key={section.id + i}
|
||||
funcData={section}
|
||||
commonFuncData={section}
|
||||
/>
|
||||
)
|
||||
case 'operation':
|
||||
return (
|
||||
<ApiOperationSection
|
||||
key={section.id + i}
|
||||
funcData={section}
|
||||
commonFuncData={section}
|
||||
spec={props.spec}
|
||||
/>
|
||||
)
|
||||
default:
|
||||
throw new Error(`Unknown common section type '${sectionType}'`)
|
||||
}
|
||||
})}
|
||||
</RefSubLayout>
|
||||
</MainSkeleton>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -240,15 +240,16 @@ When developing with Expo, you can test Sign in with Apple via the Expo Go app,
|
||||
1. Have an **App ID** which uniquely identifies the app you are building. You can create a new App ID from the [Identifiers](https://developer.apple.com/account/resources/identifiers/list/bundleId) section in the Apple Developer Console (use the filter menu in the upper right side to see all App IDs). These usually are a reverse domain name string, for example `com.example.app`. Make sure you configure Sign in with Apple for the App ID you created or already have, in the Capabilities list. At this time Supabase Auth does not support Server-to-Server notification endpoints, so you should leave that setting blank. (In the past App IDs were referred to as _bundle IDs._)
|
||||
2. Register all of the App IDs that will be using your Supabase project in the [Apple provider configuration in the Supabase dashboard](https://supabase.com/dashboard/project/_/auth/providers) under _Authorized Client IDs_.
|
||||
|
||||
<Admonition type="note">
|
||||
|
||||
If you're building a native app only, you do not need to configure the OAuth settings.
|
||||
|
||||
</Admonition>
|
||||
|
||||
## Apple sign in on Android, Web, Windows and Linux
|
||||
|
||||
For platforms that doesn't support native Apple sign in, you can use the `signInWithOAuth()` method to perform the Apple sign in.
|
||||
|
||||
<Admonition type="note">
|
||||
|
||||
Do **NOT** follow the Android or Web setup instructions on [sign_in_with_apple](https://pub.dev/packages/sign_in_with_apple) package README for these platforms. sign_in_with_apple package is not used for performing Apple sign-in on non-Apple platforms for Supabase.
|
||||
|
||||
</Admonition>
|
||||
|
||||
This method of signing in is web based, and will open a browser window to perform the sign in. For non-web platforms, the user is brought back to the app via [deep linking](/docs/guides/auth/native-mobile-deep-linking?platform=flutter).
|
||||
|
||||
```dart
|
||||
|
||||
@@ -16,7 +16,7 @@ There are three general ways to use Sign in with Google, depending on the applic
|
||||
- Sign in on the web or in web-based apps
|
||||
- Using an OAuth flow initiated by Supabase Auth using [Google Identity Authorization with OAuth 2.0 for Web Server Applications](https://developers.google.com/identity/protocols/oauth2/web-server).
|
||||
- Using a [personalized sign-in button](https://developers.google.com/identity/gsi/web/guides/personalized-button) or [One Tap](https://developers.google.com/identity/gsi/web/guides/display-google-one-tap) and [automatic sign-in](https://developers.google.com/identity/gsi/web/guides/automatic-sign-in-sign-out) for users already logged in to their Google account.
|
||||
- Sign in in native Android apps and Chrome extensions
|
||||
- Sign in in native Android apps and Chrome extensions.
|
||||
|
||||
In some cases you're able to use the OAuth flow within web-based native apps such as with React Native, Expo or other similar frameworks. It is best practice to use native Sign in with Google capabilities whenever possible.
|
||||
|
||||
@@ -232,7 +232,7 @@ Before you can use Sign in with Google, you need to obtain a [Google Cloud Platf
|
||||
|
||||
<TabPanel id="flutter" label="Flutter">
|
||||
|
||||
## Using native sign in with Google in Flutter
|
||||
## Using native sign-in with Google on Flutter
|
||||
|
||||
Native Google sign in with Supabase is done through the [google_sign_in](https://pub.dev/packages/google_sign_in) package for iOS and Android. Follow the instructions on the [google_sign_in](https://pub.dev/packages/google_sign_in) package for plugin specific settings.
|
||||
|
||||
@@ -301,11 +301,114 @@ Before you can use Sign in with Google, you need to obtain a [Google Cloud Platf
|
||||
|
||||
<TabPanel id="android" label="Android (Kotlin)">
|
||||
|
||||
Unlike the OAuth flow which requires the use of a web browser, the native Sign in with Google flow on Android uses the [operating system's built-in functionalities](https://developers.google.com/android/reference/com/google/android/gms/auth/api/identity/package-summary) to prompt the user for consent. Note that native sign-in has been rebranded as _One Tap sign-in on Android_ by Google, which you should not confuse with _One Tap sign in for web_, as mentioned below.
|
||||
## Using Google sign-in on Android
|
||||
|
||||
The Sign in with Google flow on Android uses the [operating system's built-in functionalities](https://developer.android.com/training/sign-in/credential-manager) to prompt the user for consent.
|
||||
|
||||
When the user provides consent, Google issues an identity token (commonly abbreviated as ID token) that is then sent to your project's Supabase Auth server. When valid, a new user session is started by issuing an access and refresh token from Supabase Auth.
|
||||
|
||||
When using [Compose Multiplatform](https://github.com/JetBrains/compose-multiplatform/), you can use the [compose-auth](https://supabase.com/docs/reference/kotlin/installing) plugin. On Android it uses Google OneTap (or Credential Manager on Android 14+) automatically and on other platforms it uses `auth.signInWith(Google)`.
|
||||
**Note:** You have to create OAuth client IDs for both a Web and Android application. The Web client ID is the one used in your Android app.
|
||||
|
||||
Add the following dependencies to your app. You can find the latest version of `credentials` [here](https://developer.android.com/jetpack/androidx/releases/credentials) and `googleid` [here](https://developers.google.com/identity/android-credential-manager/releases).
|
||||
|
||||
```kotlin
|
||||
implementation("androidx.credentials:credentials:<latest version>")
|
||||
implementation ("com.google.android.libraries.identity.googleid:googleid:<latest version>")
|
||||
|
||||
// optional - needed for credentials support from play services, for devices running
|
||||
// Android 13 and below.
|
||||
implementation("androidx.credentials:credentials-play-services-auth:<latest version>")
|
||||
```
|
||||
|
||||
Add the following proguard rules to your `proguard-rules.pro` file:
|
||||
|
||||
```proguard
|
||||
-if class androidx.credentials.CredentialManager
|
||||
-keep class androidx.credentials.playservices.** {
|
||||
*;
|
||||
}
|
||||
```
|
||||
|
||||
Follow the code sample below to implement native Google sign-in with Supabase using Credential Manager in your Android app.
|
||||
|
||||
```kotlin
|
||||
@Composable
|
||||
fun GoogleSignInButton() {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val context = LocalContext.current
|
||||
|
||||
val onClick: () -> Unit = {
|
||||
val credentialManager = CredentialManager.create(context)
|
||||
|
||||
// Generate a nonce and hash it with sha-256
|
||||
// Providing a nonce is optional but recommended
|
||||
val rawNonce = UUID.randomUUID().toString() // Generate a random String. UUID should be sufficient, but can also be any other random string.
|
||||
val bytes = rawNonce.toString().toByteArray()
|
||||
val md = MessageDigest.getInstance("SHA-256")
|
||||
val digest = md.digest(bytes)
|
||||
val hashedNonce = digest.fold("") { str, it -> str + "%02x".format(it) } // Hashed nonce to be passed to Google sign-in
|
||||
|
||||
|
||||
val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
|
||||
.setFilterByAuthorizedAccounts(false)
|
||||
.setServerClientId("WEB_GOOGLE_CLIENT_ID")
|
||||
.setNonce(hashedNonce) // Provide the nonce if you have one
|
||||
.build()
|
||||
|
||||
val request: GetCredentialRequest = GetCredentialRequest.Builder()
|
||||
.addCredentialOption(googleIdOption)
|
||||
.build()
|
||||
|
||||
coroutineScope.launch {
|
||||
try {
|
||||
val result = credentialManager.getCredential(
|
||||
request = request,
|
||||
context = context,
|
||||
)
|
||||
|
||||
val googleIdTokenCredential = GoogleIdTokenCredential
|
||||
.createFrom(result.credential.data)
|
||||
|
||||
val googleIdToken = googleIdTokenCredential.idToken
|
||||
|
||||
supabase.auth.signInWith(IDToken) {
|
||||
idToken = googleIdToken
|
||||
provider = Google
|
||||
nonce = rawNonce
|
||||
}
|
||||
|
||||
// Handle successful sign-in
|
||||
} catch (e: GetCredentialException) {
|
||||
// Handle GetCredentialException thrown by `credentialManager.getCredential()`
|
||||
} catch (e: GoogleIdTokenParsingException) {
|
||||
// Handle GoogleIdTokenParsingException thrown by `GoogleIdTokenCredential.createFrom()`
|
||||
} catch (e: RestException) {
|
||||
// Handle RestException thrown by Supabase
|
||||
} catch (e: Exception) {
|
||||
// Handle unknown exceptions
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Button(
|
||||
onClick = onClick,
|
||||
) {
|
||||
Text("Sign in with Google")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration [#android-configuration]
|
||||
|
||||
1. Configure OAuth credentials for your Google Cloud project in the [Credentials](https://console.cloud.google.com/apis/credentials) page of the console. You need two client IDs, a web client ID and Android client ID. When creating a new Android OAuth client ID, use the instructions on screen to provide the SHA-1 certificate fingerprint used to sign your Android app.
|
||||
2. Configure the [OAuth Consent Screen](https://console.cloud.google.com/apis/credentials/consent). This information is shown to the user when giving consent to your app. In particular, make sure you have set up links to your app's privacy policy and terms of service.
|
||||
3. Finally, add the web client ID from step 1 in the [Google provider on the Supabase Dashboard](https://supabase.com/dashboard/project/_/auth/providers), under _Authorized Client IDs_.
|
||||
|
||||
Note that you do not have to configure the OAuth flow in the Supabase Dashboard in order to use native sign in.
|
||||
|
||||
## Using Google sign-in with Kotlin Multiplatform
|
||||
|
||||
When using [Compose Multiplatform](https://www.jetbrains.com/lp/compose-multiplatform/), you can use the [compose-auth](https://supabase.com/docs/reference/kotlin/installing) plugin. On Android it uses Google OneTap (or Credential Manager on Android 14+) automatically and on other platforms it uses `auth.signInWith(Google)`.
|
||||
Alternatively, you can have a look at [Google One Tap](https://developers.google.com/identity/one-tap/android/overview), just login with the IdToken after you receive it.
|
||||
|
||||
**Initialize the Supabase Client**
|
||||
@@ -343,7 +446,7 @@ Before you can use Sign in with Google, you need to obtain a [Google Cloud Platf
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration [#kotlin-configuration-native-app]
|
||||
### Configuration [#kotlin-multiplatform-configuration]
|
||||
|
||||
1. Configure OAuth credentials for your Google Cloud project in the [Credentials](https://console.cloud.google.com/apis/credentials) page of the console. When creating a new OAuth client ID, choose _Android_ or _iOS_ depending on the mobile operating system your app is built for.
|
||||
|
||||
@@ -353,8 +456,6 @@ Before you can use Sign in with Google, you need to obtain a [Google Cloud Platf
|
||||
2. Configure the [OAuth Consent Screen](https://console.cloud.google.com/apis/credentials/consent). This information is shown to the user when giving consent to your app. In particular, make sure you have set up links to your app's privacy policy and terms of service.
|
||||
3. Finally, add the client ID from step 1 in the [Google provider on the Supabase Dashboard](https://supabase.com/dashboard/project/_/auth/providers), under _Authorized Client IDs_.
|
||||
|
||||
Note that you do not have to configure the OAuth flow in the Supabase Dashboard in order to use native sign in.
|
||||
|
||||
</TabPanel>
|
||||
|
||||
<TabPanel id="chrome-extensions" label="Chrome Extensions">
|
||||
|
||||
@@ -2,20 +2,16 @@
|
||||
id: 'functions-dart-edge'
|
||||
title: 'Dart Edge'
|
||||
description: 'Write your functions using Dart.'
|
||||
tocVideo: '53jhgrDONW4'
|
||||
---
|
||||
|
||||
[Dart Edge](https://docs.dartedge.dev/), a project built and maintained by [Invertase](https://invertase.io/), enables Dart code to be run on different edge environments. This guide will walk you through how you can start using Dart Edge to write your backend code using Dart and run it on Supabase.
|
||||
|
||||
> ⚠️ WARNING: Dart Edge is an experimental project - it's probably not ready for production usage unless you're okay with living on the 'edge'. Open issues on [Dart Edge repo](https://github.com/invertase/dart_edge) if you encounter any issues.
|
||||
<Admonition type="caution">
|
||||
|
||||
<div class="video-container">
|
||||
<iframe
|
||||
src="https://www.youtube-nocookie.com/embed/53jhgrDONW4"
|
||||
frameBorder="1"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
</div>
|
||||
Dart Edge is an experimental project - it's probably not ready for production usage unless you're okay with living on the 'edge'. Open issues on [Dart Edge repo](https://github.com/invertase/dart_edge) if you encounter any issues.
|
||||
|
||||
</Admonition>
|
||||
|
||||
## Pre requirements
|
||||
|
||||
@@ -122,10 +118,29 @@ void main() {
|
||||
|
||||
### Run locally
|
||||
|
||||
Create a `edge.yaml` file if you don't have one yet in the root of your project. Then, add the following configuration to specify the path to your Supabase project.
|
||||
|
||||
```yaml
|
||||
supabase:
|
||||
project_path: './supabase'
|
||||
```
|
||||
|
||||
Also, currently Dart Edge doesn't work with the latest versions of Flutter. If you do have the latest version of Flutter on your machine, you can use [FVM](https://fvm.app/) to use an older version of Flutter for your Dart Edge project.
|
||||
|
||||
```bash
|
||||
fvm use 3.7.12 -f
|
||||
```
|
||||
|
||||
You can read more about how to configure FVM (Flutter
|
||||
Version Management) for your project in the [FVM documentation](https://fvm.app/documentation/getting-started).
|
||||
|
||||
Run the following command to compile your Dart code. This command will start a watcher that will recompile anytime you make changes to your code.
|
||||
|
||||
```bash
|
||||
edge build supabase_functions --dev
|
||||
|
||||
# Or with FVM
|
||||
fvm dart pub run edge build supabase_functions --dev
|
||||
```
|
||||
|
||||
With docker running, start your local Supabase with the following command
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
---
|
||||
title: 'IPv4 Address'
|
||||
title: 'Dedicated IPv4 Address'
|
||||
description: 'Attach an IPv4 address to your database'
|
||||
subtitle: 'Attach an IPv4 address to your database'
|
||||
---
|
||||
|
||||
From 26th January 2024, we will begin migrating projects to IPv6. To read more about why we are doing this migration, read [this blog post](https://supabase.com/blog/ipv6) and [this discussion](https://github.com/orgs/supabase/discussions/17817) for how to prepare for the migration. As a summary, AWS will [start charging for IPv4 addresses](https://aws.amazon.com/blogs/aws/new-aws-public-ipv4-address-charge-public-ip-insights/).
|
||||
|
||||
The add-on is $4 per month - we're passing on the AWS costs to you. The add-on is available for all paid plans.
|
||||
|
||||
## When is this add-on required?
|
||||
@@ -25,7 +23,7 @@ When you purchase this add-on, your project won't be migrated to IPv6. PGBouncer
|
||||
|
||||
## Enabling the add-on
|
||||
|
||||
You can now enable the IPv4 add-on in your project [add-on settings](https://supabase.com/dashboard/project/_/settings/addons) page.
|
||||
You can enable the IPv4 add-on in your project [add-on settings](https://supabase.com/dashboard/project/_/settings/addons) page.
|
||||
|
||||
<Admonition type="caution" label="Downtime when add-on is toggled.">
|
||||
Note that there might be some downtime when toggling the add-on since some DNS clients might have
|
||||
@@ -33,6 +31,10 @@ You can now enable the IPv4 add-on in your project [add-on settings](https://sup
|
||||
Generally, this should be less than a minute.
|
||||
</Admonition>
|
||||
|
||||
<Image alt="IPv4 add-on page" src="/docs/img/guides/platform/ipv4/ipv4-addon-page.png" />
|
||||
## Caveats
|
||||
|
||||
<Image alt="IPv4 add-on page" src="/docs/img/guides/platform/ipv4/ipv4-enable.png" />
|
||||
For regular use-cases like a restart or compute size changes, the IPv4 address remains unchanged.
|
||||
However, there are cases where maintaining the same IPv4 address isn't guaranteed. These include:
|
||||
|
||||
- If the project gets paused and unpaused
|
||||
- If the add-on gets removed and added again
|
||||
@@ -22,12 +22,14 @@ Resources:
|
||||
|
||||
## In production
|
||||
|
||||
Once your application is live, you should never change your database using the Dashboard. Supabase provides various [access levels](https://supabase.com/docs/guides/platform/access-control) for the Dashboard that can help enforce this. Some other important things to consider at this point include:
|
||||
Once your application is live, you should never change your database using the Dashboard - everything should be done with [Migrations](/docs/guides/cli/managing-environments#create-a-new-migration). Some other important things to consider at this point include:
|
||||
|
||||
- Read the [Production Checklist](/docs/guides/platform/going-into-prod).
|
||||
- Make your team aware of the [Shared Responsibilities](/docs/guides/platform/shared-responsibility-model) between your organization and Supabase.
|
||||
- Design a [safe workflow](https://supabase.com/docs/guides/platform/shared-responsibility-model#you-decide-your-own-workflow) for managing your database. We strongly recommend running [multiple environments](/docs/guides/cli/managing-environments) as part of your development workflow (`local` -> `staging` -> `prod`).
|
||||
- The Dashboard has various [access levels](/docs/guides/platform/access-control) that can prevent changes being made via the UI.
|
||||
- Design a [safe workflow](/docs/guides/platform/shared-responsibility-model#you-decide-your-own-workflow) for managing your database. We strongly recommend running [multiple environments](/docs/guides/cli/managing-environments) as part of your development workflow (`local` -> `staging` -> `prod`).
|
||||
- Do not share any production passwords with your team, _especially_ your `postgres` password. All changes should be made via version-controlled migrations which run via a bastion host or a CI platform (like [GitHub Actions](/docs/guides/cli/managing-environments#configure-github-actions). If you use GitHub Actions, use [approval workflows](https://docs.github.com/en/actions/managing-workflow-runs/reviewing-deployments) to prevent any migrations being run accidentally.
|
||||
- Restrict production access to your database using [Network Restrictions](/docs/guides/platform/network-restrictions).
|
||||
- As your database to grows, we strongly recommend moving to [Point-in-Time Recovery](/docs/guides/platform/backups#point-in-time-recovery). This is safer and has less impact on your database performance during maintenance windows.
|
||||
- Read the [Production Checklist](/docs/guides/platform/going-into-prod) and familiarize your team with the [Shared Responsibilities](/docs/guides/platform/shared-responsibility-model) between your organization and Supabase.
|
||||
|
||||
Resources:
|
||||
|
||||
|
||||
@@ -135,16 +135,22 @@ All settings made through the dashboard will be propagated across all databases
|
||||
A project needs to satisfy these requirements to spin up a read replica:
|
||||
|
||||
1. Running on AWS.
|
||||
- Support for projects on Fly is in progress.
|
||||
2. Running on at least a small compute.
|
||||
3. PostgreSQL 15.
|
||||
- For projects running on older versions of PostgreSQL, you can initiate self-serve upgrades with pg_upgrade. For details, see the [upgrade guide](/docs/guides/platform/migrating-and-upgrading-projects#pgupgrade).
|
||||
- Support for projects on Fly.io will be added at a later date.
|
||||
1. Running on at least a [Small compute add-on](/docs/guides/platform/compute-add-ons).
|
||||
1. Using [physical backups](/docs/guides/platform/backups#point-in-time-recovery)
|
||||
- Physical backups are automatically enabled if using [PITR](/docs/guides/platform/backups#point-in-time-recovery)
|
||||
1. Running on Postgres 15.
|
||||
- For projects running on older versions of PostgreSQL, you will need to [upgrade to the latest platform version](/docs/guides/platform/migrating-and-upgrading-projects#pgupgrade).
|
||||
|
||||
### Read replicas need to be brought down before starting the following procedures
|
||||
|
||||
The following procedures require all read replicas for a project to be brought down before they can be started:
|
||||
|
||||
1. Upgrading a project via pg_upgrade.
|
||||
2. Performing data restoration.
|
||||
1. [Upgrading a project](/docs/guides/platform/migrating-and-upgrading-projects#pgupgrade)
|
||||
1. Performing [data restoration](/docs/guides/platform/backups#pitr-restoration-process).
|
||||
|
||||
Changes made to the primary database during these operations heavily disrupt replication and potentially leave active read replicas in unstable states. Once these operations complete, read replicas can be spun back up.
|
||||
Once these operations complete, read replicas can be spun back up.
|
||||
|
||||
### Compute Add-ons
|
||||
|
||||
In order to avoid replicas being unable to keep up with activity on the primaries they're following, Read Replicas are currently placed on the same Compute Add-on as the primary they're following.
|
||||
@@ -7,11 +7,6 @@ export const menuState = proxy({
|
||||
setMenuActiveRefId: (value) => {
|
||||
menuState.menuActiveRefId = value
|
||||
},
|
||||
menuLevelId: 'home',
|
||||
setMenuLevelId: (value) => {
|
||||
menuState.menuMobileOpen = false
|
||||
menuState.menuLevelId = value
|
||||
},
|
||||
menuMobileOpen: false,
|
||||
setMenuMobileOpen: (value) => {
|
||||
menuState.menuMobileOpen = value
|
||||
@@ -21,9 +16,6 @@ export const menuState = proxy({
|
||||
export const useMenuActiveRefId = () => {
|
||||
return useSnapshot(menuState).menuActiveRefId
|
||||
}
|
||||
export const useMenuLevelId = () => {
|
||||
return useSnapshot(menuState).menuLevelId
|
||||
}
|
||||
|
||||
export const useMenuMobileOpen = () => {
|
||||
return useSnapshot(menuState).menuMobileOpen
|
||||
|
||||
@@ -45,7 +45,6 @@ async function generate() {
|
||||
<url>
|
||||
<loc>${`https://supabase.com/docs/${path}`}</loc>
|
||||
<changefreq>weekly</changefreq>
|
||||
<changefreq>0.5</changefreq>
|
||||
</url>
|
||||
`
|
||||
})
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { FC } from 'react'
|
||||
import { FooterHelpCalloutType } from '~/components/FooterHelpCallout'
|
||||
import { type MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import GuideLayout from './guides'
|
||||
|
||||
interface Props {
|
||||
@@ -16,6 +17,7 @@ interface Props {
|
||||
hideToc?: boolean
|
||||
currentPage?: string
|
||||
editLink?: string
|
||||
menuId: MenuId
|
||||
}
|
||||
|
||||
const Layout: FC<Props> = (props) => {
|
||||
|
||||
@@ -5,6 +5,7 @@ import { useRouter } from 'next/router'
|
||||
import { FC, PropsWithChildren } from 'react'
|
||||
import components from '~/components'
|
||||
import TableOfContents from '~/components/TableOfContents'
|
||||
import { MainSkeleton } from './MainSkeleton'
|
||||
|
||||
interface Props {
|
||||
meta: {
|
||||
|
||||
@@ -4,9 +4,11 @@ import Head from 'next/head'
|
||||
import { useRouter } from 'next/router'
|
||||
import { FC } from 'react'
|
||||
import components from '~/components'
|
||||
import HomePageCover from '~/components/HomePageCover'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import TableOfContents from '~/components/TableOfContents'
|
||||
import HomePageCover from '../components/HomePageCover'
|
||||
import { LayoutMainContent } from './DefaultLayout'
|
||||
import { MainSkeleton } from './MainSkeleton'
|
||||
|
||||
interface Props {
|
||||
meta: {
|
||||
@@ -61,26 +63,28 @@ const HomeLayout: FC<Props> = (props: Props) => {
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<article>
|
||||
<HomePageCover meta={props.meta} />
|
||||
<LayoutMainContent>
|
||||
<div className={['relative transition-all ease-out', 'duration-150 '].join(' ')}>
|
||||
<div className="prose max-w-none">
|
||||
<MDXProvider components={components}>{props.children}</MDXProvider>
|
||||
<MainSkeleton menuId={MenuId.Home}>
|
||||
<article>
|
||||
<HomePageCover meta={props.meta} />
|
||||
<LayoutMainContent>
|
||||
<div className={['relative transition-all ease-out', 'duration-150 '].join(' ')}>
|
||||
<div className="prose max-w-none">
|
||||
<MDXProvider components={components}>{props.children}</MDXProvider>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{hasTableOfContents && !props.meta?.hide_table_of_contents && (
|
||||
<div
|
||||
className={[
|
||||
'border-default bg-background table-of-contents-height border-l',
|
||||
'thin-scrollbar overflow-y-auto sticky hidden md:block md:col-span-3 px-2',
|
||||
].join(' ')}
|
||||
>
|
||||
<TableOfContents toc={props.toc} video={props.meta.video} />
|
||||
</div>
|
||||
)}
|
||||
</LayoutMainContent>
|
||||
</article>
|
||||
{hasTableOfContents && !props.meta?.hide_table_of_contents && (
|
||||
<div
|
||||
className={[
|
||||
'border-default bg-background table-of-contents-height border-l',
|
||||
'thin-scrollbar overflow-y-auto sticky hidden md:block md:col-span-3 px-2',
|
||||
].join(' ')}
|
||||
>
|
||||
<TableOfContents toc={props.toc} video={props.meta.video} />
|
||||
</div>
|
||||
)}
|
||||
</LayoutMainContent>
|
||||
</article>
|
||||
</MainSkeleton>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,376 @@
|
||||
import { useTheme } from 'next-themes'
|
||||
import Image from 'next/legacy/image'
|
||||
import Link from 'next/link'
|
||||
import NavigationMenu, { type MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import TopNavBar from '~/components/Navigation/NavigationMenu/TopNavBar'
|
||||
|
||||
import { PropsWithChildren, memo, useEffect } from 'react'
|
||||
import Footer from '~/components/Navigation/Footer'
|
||||
import { menuState, useMenuMobileOpen } from '~/hooks/useMenuState'
|
||||
|
||||
const levelsData = {
|
||||
home: {
|
||||
icon: '/docs/img/icons/menu/home',
|
||||
name: 'Home',
|
||||
},
|
||||
gettingstarted: {
|
||||
icon: '/docs/img/icons/menu/getting-started',
|
||||
name: 'Getting Started',
|
||||
},
|
||||
database: {
|
||||
icon: '/docs/img/icons/menu/database',
|
||||
name: 'Database',
|
||||
},
|
||||
api: {
|
||||
icon: '/docs/img/icons/menu/rest',
|
||||
name: 'REST API',
|
||||
},
|
||||
graphql: {
|
||||
icon: '/docs/img/icons/menu/graphql',
|
||||
name: 'GraphQL',
|
||||
},
|
||||
auth: {
|
||||
icon: '/docs/img/icons/menu/auth',
|
||||
name: 'Auth',
|
||||
},
|
||||
functions: {
|
||||
icon: '/docs/img/icons/menu/functions',
|
||||
name: 'Edge Functions',
|
||||
},
|
||||
realtime: {
|
||||
icon: '/docs/img/icons/menu/realtime',
|
||||
name: 'Realtime',
|
||||
},
|
||||
analytics: {
|
||||
icon: '/docs/img/icons/menu/analytics',
|
||||
name: 'Analytics',
|
||||
},
|
||||
storage: {
|
||||
icon: '/docs/img/icons/menu/storage',
|
||||
name: 'Storage',
|
||||
},
|
||||
ai: {
|
||||
icon: '/docs/img/icons/menu/ai',
|
||||
name: 'AI & Vectors',
|
||||
},
|
||||
supabase_cli: {
|
||||
icon: '/docs/img/icons/menu/reference-cli',
|
||||
name: 'Supabase CLI',
|
||||
},
|
||||
platform: {
|
||||
icon: '/docs/img/icons/menu/platform',
|
||||
name: 'Platform',
|
||||
},
|
||||
resources: {
|
||||
icon: '/docs/img/icons/menu/resources',
|
||||
name: 'Resources',
|
||||
},
|
||||
self_hosting: {
|
||||
icon: '/docs/img/icons/menu/self-hosting',
|
||||
name: 'Self-Hosting',
|
||||
},
|
||||
integrations: {
|
||||
icon: '/docs/img/icons/menu/integrations',
|
||||
name: 'Integrations',
|
||||
},
|
||||
reference_javascript_v1: {
|
||||
icon: '/docs/img/icons/menu/reference-javascript',
|
||||
name: 'Javascript Reference v1.0',
|
||||
},
|
||||
reference_javascript_v2: {
|
||||
icon: '/docs/img/icons/menu/reference-javascript',
|
||||
name: 'Javascript Reference v2.0',
|
||||
},
|
||||
reference_dart_v1: {
|
||||
icon: '/docs/img/icons/menu/reference-dart',
|
||||
name: 'Dart Reference v1.0',
|
||||
},
|
||||
reference_dart_v2: {
|
||||
icon: '/docs/img/icons/menu/reference-dart',
|
||||
name: 'Dart Reference v2.0',
|
||||
},
|
||||
reference_csharp_v0: {
|
||||
icon: '/docs/img/icons/menu/reference-csharp',
|
||||
name: 'C# Reference v0.0',
|
||||
},
|
||||
reference_python_v2: {
|
||||
icon: '/docs/img/icons/menu/reference-python',
|
||||
name: 'Python Reference v2.0',
|
||||
},
|
||||
reference_swift_v1: {
|
||||
icon: '/docs/img/icons/menu/reference-swift',
|
||||
name: 'Swift Reference v1.0',
|
||||
},
|
||||
reference_swift_v2: {
|
||||
icon: '/docs/img/icons/menu/reference-swift',
|
||||
name: 'Swift Reference v2.0',
|
||||
},
|
||||
reference_kotlin_v1: {
|
||||
icon: '/docs/img/icons/menu/reference-kotlin',
|
||||
name: 'Kotlin Reference v1.0',
|
||||
},
|
||||
reference_kotlin_v2: {
|
||||
icon: '/docs/img/icons/menu/reference-kotlin',
|
||||
name: 'Kotlin Reference v2.0',
|
||||
},
|
||||
reference_cli: {
|
||||
icon: '/docs/img/icons/menu/reference-cli',
|
||||
name: 'CLI Reference',
|
||||
},
|
||||
reference_api: {
|
||||
icon: '/docs/img/icons/menu/reference-api',
|
||||
name: 'Management API Reference',
|
||||
},
|
||||
reference_self_hosting_auth: {
|
||||
icon: '/docs/img/icons/menu/reference-auth',
|
||||
name: 'Auth Server Reference',
|
||||
},
|
||||
reference_self_hosting_storage: {
|
||||
icon: '/docs/img/icons/menu/reference-storage',
|
||||
name: 'Storage Server Reference',
|
||||
},
|
||||
reference_self_hosting_realtime: {
|
||||
icon: '/docs/img/icons/menu/reference-realtime',
|
||||
name: 'Realtime Server Reference',
|
||||
},
|
||||
reference_self_hosting_analytics: {
|
||||
icon: '/docs/img/icons/menu/reference-analytics',
|
||||
name: 'Analytics Server Reference',
|
||||
},
|
||||
reference_self_hosting_functions: {
|
||||
icon: '/docs/img/icons/menu/reference-functions',
|
||||
name: 'Functions Server Reference',
|
||||
},
|
||||
}
|
||||
|
||||
const MobileHeader = memo(function MobileHeader({ menuId }: { menuId: MenuId }) {
|
||||
const mobileMenuOpen = useMenuMobileOpen()
|
||||
const menuLevel = menuId
|
||||
|
||||
return (
|
||||
<div
|
||||
className={[
|
||||
'transition-all ease-out z-10',
|
||||
'top-0',
|
||||
mobileMenuOpen && 'absolute',
|
||||
'flex items-center h-[40px]',
|
||||
mobileMenuOpen ? 'gap-0' : 'gap-3',
|
||||
].join(' ')}
|
||||
>
|
||||
<button
|
||||
className={['mr-2', mobileMenuOpen && 'mt-0.5'].join(' ')}
|
||||
onClick={() => menuState.setMenuMobileOpen(!mobileMenuOpen)}
|
||||
>
|
||||
<div
|
||||
className={[
|
||||
'space-y-1 group cursor-pointer relative',
|
||||
mobileMenuOpen ? 'w-4 h-4' : 'w-4 h-[8px]',
|
||||
].join(' ')}
|
||||
>
|
||||
<span
|
||||
className={[
|
||||
'transition-all ease-out block w-4 h-px bg-foreground-muted group-hover:bg-foreground',
|
||||
!mobileMenuOpen ? 'w-4' : 'absolute rotate-45 top-[6px]',
|
||||
].join(' ')}
|
||||
></span>
|
||||
<span
|
||||
className={[
|
||||
'transition-all ease-out block h-px bg-foreground-muted group-hover:bg-foreground',
|
||||
!mobileMenuOpen ? 'w-3 group-hover:w-4' : 'absolute w-4 -rotate-45 top-[2px]',
|
||||
].join(' ')}
|
||||
></span>
|
||||
</div>
|
||||
</button>
|
||||
<div className={[].join(' ')}>
|
||||
<img
|
||||
src={menuLevel ? levelsData[menuLevel].icon + '.svg' : levelsData['home'].icon + '.svg'}
|
||||
className={[
|
||||
'transition-all duration-200',
|
||||
mobileMenuOpen ? 'invisible w-0 h-0' : 'w-4 h-4',
|
||||
].join(' ')}
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
className={[
|
||||
'transition-all duration-200',
|
||||
'text-foreground',
|
||||
mobileMenuOpen ? 'text-xs' : 'text-sm',
|
||||
].join(' ')}
|
||||
>
|
||||
{mobileMenuOpen
|
||||
? 'Close'
|
||||
: menuLevel
|
||||
? levelsData[menuLevel].name
|
||||
: levelsData['home'].name}
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
const MobileMenuBackdrop = memo(function MobileMenuBackdrop() {
|
||||
const mobileMenuOpen = useMenuMobileOpen()
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('resize', (e: UIEvent) => {
|
||||
const w = e.target as Window
|
||||
if (mobileMenuOpen && w.innerWidth >= 1024) {
|
||||
menuState.setMenuMobileOpen(!mobileMenuOpen)
|
||||
}
|
||||
})
|
||||
return () => {
|
||||
window.removeEventListener('resize', () => {})
|
||||
}
|
||||
}, [mobileMenuOpen])
|
||||
|
||||
return (
|
||||
<div
|
||||
className={[
|
||||
'h-full',
|
||||
'left-0',
|
||||
'right-0',
|
||||
'z-10',
|
||||
'backdrop-blur-sm backdrop-filter bg-alternative/90',
|
||||
mobileMenuOpen ? 'absolute h-full w-full top-0 left-0' : 'hidden h-0',
|
||||
// always hide on desktop
|
||||
'lg:hidden',
|
||||
].join(' ')}
|
||||
onClick={() => menuState.setMenuMobileOpen(!mobileMenuOpen)}
|
||||
></div>
|
||||
)
|
||||
})
|
||||
|
||||
const HeaderLogo = memo(function HeaderLogo() {
|
||||
const { resolvedTheme } = useTheme()
|
||||
return (
|
||||
<Link href="/" className="px-10 flex items-center gap-2">
|
||||
<Image
|
||||
className="cursor-pointer"
|
||||
src={
|
||||
resolvedTheme?.includes('dark') ? '/docs/supabase-dark.svg' : '/docs/supabase-light.svg'
|
||||
}
|
||||
width={96}
|
||||
height={24}
|
||||
alt="Supabase Logo"
|
||||
/>
|
||||
<span className="font-mono text-sm font-medium text-brand-link">DOCS</span>
|
||||
</Link>
|
||||
)
|
||||
})
|
||||
|
||||
const Container = memo(function Container(props: PropsWithChildren) {
|
||||
const mobileMenuOpen = useMenuMobileOpen()
|
||||
|
||||
return (
|
||||
<div
|
||||
// #docs-content-container is used by layout to scroll to top
|
||||
id="docs-content-container"
|
||||
className={[
|
||||
// 'overflow-x-auto',
|
||||
'w-full transition-all ease-out',
|
||||
// 'absolute lg:relative',
|
||||
mobileMenuOpen ? 'ml-[75%] sm:ml-[50%] md:ml-[33%] overflow-hidden' : 'overflow-auto',
|
||||
// desktop override any margin styles
|
||||
'lg:ml-0',
|
||||
].join(' ')}
|
||||
>
|
||||
<div className="flex flex-col relative">{props.children}</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
const NavContainer = memo(function NavContainer({ menuId }: { menuId: MenuId }) {
|
||||
const mobileMenuOpen = useMenuMobileOpen()
|
||||
|
||||
return (
|
||||
<nav
|
||||
aria-labelledby="main-nav-title"
|
||||
className={[
|
||||
// 'hidden',
|
||||
'absolute lg:relative',
|
||||
mobileMenuOpen ? 'w-[75%] sm:w-[50%] md:w-[33%] left-0' : 'w-0 -left-[280px]',
|
||||
'lg:w-[420px] !lg:left-0',
|
||||
// desktop override any left styles
|
||||
'lg:left-0',
|
||||
'transition-all',
|
||||
'top-0',
|
||||
'flex flex-col ml-0',
|
||||
].join(' ')}
|
||||
>
|
||||
<div
|
||||
className={[
|
||||
'top-0',
|
||||
'relative',
|
||||
'w-auto',
|
||||
'border-r overflow-auto h-screen',
|
||||
'backdrop-blur backdrop-filter bg-background',
|
||||
'flex flex-col',
|
||||
].join(' ')}
|
||||
>
|
||||
<h1 id="main-nav-title" className="sr-only">
|
||||
Main menu
|
||||
</h1>
|
||||
<div className="top-0 sticky z-10">
|
||||
<div>
|
||||
<div>
|
||||
<div
|
||||
className={[
|
||||
'hidden lg:flex lg:height-auto',
|
||||
'pt-8 bg-background flex-col gap-8',
|
||||
].join(' ')}
|
||||
>
|
||||
<HeaderLogo />
|
||||
</div>
|
||||
<div className="h-4 bg-background w-full"></div>
|
||||
<div className="bg-gradient-to-b from-background to-transparent h-4 w-full"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={[
|
||||
'transition-all ease-out duration-200',
|
||||
'absolute left-0 right-0 h-screen',
|
||||
'px-5 pl-5 py-16',
|
||||
'top-[0px]',
|
||||
'bg-background',
|
||||
// desktop styles
|
||||
'lg:relative lg:top-0 lg:left-0 lg:pb-10 lg:px-10 lg:pt-0 lg:flex',
|
||||
'lg:opacity-100 lg:visible',
|
||||
].join(' ')}
|
||||
>
|
||||
<NavigationMenu menuId={menuId} />
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
)
|
||||
})
|
||||
|
||||
function MainSkeleton({ children, menuId }: PropsWithChildren<{ menuId: MenuId }>) {
|
||||
return (
|
||||
<div className="flex flex-row h-full">
|
||||
<NavContainer menuId={menuId} />
|
||||
<Container>
|
||||
<div className={['lg:sticky top-0 z-10 overflow-hidden'].join(' ')}>
|
||||
<TopNavBar />
|
||||
</div>
|
||||
<div
|
||||
className={[
|
||||
'sticky transition-all top-0',
|
||||
'z-10',
|
||||
'backdrop-blur backdrop-filter bg-background',
|
||||
].join(' ')}
|
||||
>
|
||||
<div className={['lg:hidden', 'px-5 ', 'border-b z-10'].join(' ')}>
|
||||
<MobileHeader menuId={menuId} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="grow">
|
||||
{children}
|
||||
<Footer />
|
||||
</div>
|
||||
<MobileMenuBackdrop />
|
||||
</Container>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export { MainSkeleton }
|
||||
@@ -1,349 +1,5 @@
|
||||
import { useTheme } from 'next-themes'
|
||||
import Image from 'next/legacy/image'
|
||||
import Link from 'next/link'
|
||||
import NavigationMenu from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import TopNavBar from '~/components/Navigation/NavigationMenu/TopNavBar'
|
||||
|
||||
import Head from 'next/head'
|
||||
import { PropsWithChildren, memo, useEffect } from 'react'
|
||||
import Footer from '~/components/Navigation/Footer'
|
||||
import { menuState, useMenuLevelId, useMenuMobileOpen } from '~/hooks/useMenuState'
|
||||
|
||||
const levelsData = {
|
||||
home: {
|
||||
icon: '/docs/img/icons/menu/home',
|
||||
name: 'Home',
|
||||
},
|
||||
gettingstarted: {
|
||||
icon: '/docs/img/icons/menu/getting-started',
|
||||
name: 'Getting Started',
|
||||
},
|
||||
database: {
|
||||
icon: '/docs/img/icons/menu/database',
|
||||
name: 'Database',
|
||||
},
|
||||
api: {
|
||||
icon: '/docs/img/icons/menu/rest',
|
||||
name: 'REST API',
|
||||
},
|
||||
graphql: {
|
||||
icon: '/docs/img/icons/menu/graphql',
|
||||
name: 'GraphQL',
|
||||
},
|
||||
auth: {
|
||||
icon: '/docs/img/icons/menu/auth',
|
||||
name: 'Auth',
|
||||
},
|
||||
functions: {
|
||||
icon: '/docs/img/icons/menu/functions',
|
||||
name: 'Edge Functions',
|
||||
},
|
||||
realtime: {
|
||||
icon: '/docs/img/icons/menu/realtime',
|
||||
name: 'Realtime',
|
||||
},
|
||||
analytics: {
|
||||
icon: '/docs/img/icons/menu/analytics',
|
||||
name: 'Analytics',
|
||||
},
|
||||
storage: {
|
||||
icon: '/docs/img/icons/menu/storage',
|
||||
name: 'Storage',
|
||||
},
|
||||
ai: {
|
||||
icon: '/docs/img/icons/menu/ai',
|
||||
name: 'AI & Vectors',
|
||||
},
|
||||
supabase_cli: {
|
||||
icon: '/docs/img/icons/menu/reference-cli',
|
||||
name: 'Supabase CLI',
|
||||
},
|
||||
platform: {
|
||||
icon: '/docs/img/icons/menu/platform',
|
||||
name: 'Platform',
|
||||
},
|
||||
resources: {
|
||||
icon: '/docs/img/icons/menu/resources',
|
||||
name: 'Resources',
|
||||
},
|
||||
self_hosting: {
|
||||
icon: '/docs/img/icons/menu/self-hosting',
|
||||
name: 'Self-Hosting',
|
||||
},
|
||||
integrations: {
|
||||
icon: '/docs/img/icons/menu/integrations',
|
||||
name: 'Integrations',
|
||||
},
|
||||
reference_javascript_v1: {
|
||||
icon: '/docs/img/icons/menu/reference-javascript',
|
||||
name: 'Javascript Reference v1.0',
|
||||
},
|
||||
reference_javascript_v2: {
|
||||
icon: '/docs/img/icons/menu/reference-javascript',
|
||||
name: 'Javascript Reference v2.0',
|
||||
},
|
||||
reference_dart_v1: {
|
||||
icon: '/docs/img/icons/menu/reference-dart',
|
||||
name: 'Dart Reference v1.0',
|
||||
},
|
||||
reference_dart_v2: {
|
||||
icon: '/docs/img/icons/menu/reference-dart',
|
||||
name: 'Dart Reference v2.0',
|
||||
},
|
||||
reference_csharp_v0: {
|
||||
icon: '/docs/img/icons/menu/reference-csharp',
|
||||
name: 'C# Reference v0.0',
|
||||
},
|
||||
reference_python_v2: {
|
||||
icon: '/docs/img/icons/menu/reference-python',
|
||||
name: 'Python Reference v2.0',
|
||||
},
|
||||
reference_swift_v1: {
|
||||
icon: '/docs/img/icons/menu/reference-swift',
|
||||
name: 'Swift Reference v1.0',
|
||||
},
|
||||
reference_swift_v2: {
|
||||
icon: '/docs/img/icons/menu/reference-swift',
|
||||
name: 'Swift Reference v2.0',
|
||||
},
|
||||
reference_kotlin_v1: {
|
||||
icon: '/docs/img/icons/menu/reference-kotlin',
|
||||
name: 'Kotlin Reference v1.0',
|
||||
},
|
||||
reference_kotlin_v2: {
|
||||
icon: '/docs/img/icons/menu/reference-kotlin',
|
||||
name: 'Kotlin Reference v2.0',
|
||||
},
|
||||
reference_cli: {
|
||||
icon: '/docs/img/icons/menu/reference-cli',
|
||||
name: 'CLI Reference',
|
||||
},
|
||||
reference_api: {
|
||||
icon: '/docs/img/icons/menu/reference-api',
|
||||
name: 'Management API Reference',
|
||||
},
|
||||
reference_self_hosting_auth: {
|
||||
icon: '/docs/img/icons/menu/reference-auth',
|
||||
name: 'Auth Server Reference',
|
||||
},
|
||||
reference_self_hosting_storage: {
|
||||
icon: '/docs/img/icons/menu/reference-storage',
|
||||
name: 'Storage Server Reference',
|
||||
},
|
||||
reference_self_hosting_realtime: {
|
||||
icon: '/docs/img/icons/menu/reference-realtime',
|
||||
name: 'Realtime Server Reference',
|
||||
},
|
||||
reference_self_hosting_analytics: {
|
||||
icon: '/docs/img/icons/menu/reference-analytics',
|
||||
name: 'Analytics Server Reference',
|
||||
},
|
||||
reference_self_hosting_functions: {
|
||||
icon: '/docs/img/icons/menu/reference-functions',
|
||||
name: 'Functions Server Reference',
|
||||
},
|
||||
}
|
||||
|
||||
const MobileHeader = memo(function MobileHeader() {
|
||||
const mobileMenuOpen = useMenuMobileOpen()
|
||||
const menuLevel = useMenuLevelId()
|
||||
|
||||
return (
|
||||
<div
|
||||
className={[
|
||||
'transition-all ease-out z-10',
|
||||
'top-0',
|
||||
mobileMenuOpen && 'absolute',
|
||||
'flex items-center h-[40px]',
|
||||
mobileMenuOpen ? 'gap-0' : 'gap-3',
|
||||
].join(' ')}
|
||||
>
|
||||
<button
|
||||
className={['mr-2', mobileMenuOpen && 'mt-0.5'].join(' ')}
|
||||
onClick={() => menuState.setMenuMobileOpen(!mobileMenuOpen)}
|
||||
>
|
||||
<div
|
||||
className={[
|
||||
'space-y-1 group cursor-pointer relative',
|
||||
mobileMenuOpen ? 'w-4 h-4' : 'w-4 h-[8px]',
|
||||
].join(' ')}
|
||||
>
|
||||
<span
|
||||
className={[
|
||||
'transition-all ease-out block w-4 h-px bg-foreground-muted group-hover:bg-foreground',
|
||||
!mobileMenuOpen ? 'w-4' : 'absolute rotate-45 top-[6px]',
|
||||
].join(' ')}
|
||||
></span>
|
||||
<span
|
||||
className={[
|
||||
'transition-all ease-out block h-px bg-foreground-muted group-hover:bg-foreground',
|
||||
!mobileMenuOpen ? 'w-3 group-hover:w-4' : 'absolute w-4 -rotate-45 top-[2px]',
|
||||
].join(' ')}
|
||||
></span>
|
||||
</div>
|
||||
</button>
|
||||
<div className={[].join(' ')}>
|
||||
<img
|
||||
src={menuLevel ? levelsData[menuLevel].icon + '.svg' : levelsData['home'].icon + '.svg'}
|
||||
className={[
|
||||
'transition-all duration-200',
|
||||
mobileMenuOpen ? 'invisible w-0 h-0' : 'w-4 h-4',
|
||||
].join(' ')}
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
className={[
|
||||
'transition-all duration-200',
|
||||
'text-foreground',
|
||||
mobileMenuOpen ? 'text-xs' : 'text-sm',
|
||||
].join(' ')}
|
||||
>
|
||||
{mobileMenuOpen
|
||||
? 'Close'
|
||||
: menuLevel
|
||||
? levelsData[menuLevel].name
|
||||
: levelsData['home'].name}
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
const MobileMenuBackdrop = memo(function MobileMenuBackdrop() {
|
||||
const mobileMenuOpen = useMenuMobileOpen()
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('resize', (e: UIEvent) => {
|
||||
const w = e.target as Window
|
||||
if (mobileMenuOpen && w.innerWidth >= 1024) {
|
||||
menuState.setMenuMobileOpen(!mobileMenuOpen)
|
||||
}
|
||||
})
|
||||
return () => {
|
||||
window.removeEventListener('resize', () => {})
|
||||
}
|
||||
}, [mobileMenuOpen])
|
||||
|
||||
return (
|
||||
<div
|
||||
className={[
|
||||
'h-full',
|
||||
'left-0',
|
||||
'right-0',
|
||||
'z-10',
|
||||
'backdrop-blur-sm backdrop-filter bg-alternative/90',
|
||||
mobileMenuOpen ? 'absolute h-full w-full top-0 left-0' : 'hidden h-0',
|
||||
// always hide on desktop
|
||||
'lg:hidden',
|
||||
].join(' ')}
|
||||
onClick={() => menuState.setMenuMobileOpen(!mobileMenuOpen)}
|
||||
></div>
|
||||
)
|
||||
})
|
||||
|
||||
const HeaderLogo = memo(function HeaderLogo() {
|
||||
const { resolvedTheme } = useTheme()
|
||||
return (
|
||||
<Link href="/" className="px-10 flex items-center gap-2">
|
||||
<Image
|
||||
className="cursor-pointer"
|
||||
src={
|
||||
resolvedTheme?.includes('dark') ? '/docs/supabase-dark.svg' : '/docs/supabase-light.svg'
|
||||
}
|
||||
width={96}
|
||||
height={24}
|
||||
alt="Supabase Logo"
|
||||
/>
|
||||
<span className="font-mono text-sm font-medium text-brand-link">DOCS</span>
|
||||
</Link>
|
||||
)
|
||||
})
|
||||
|
||||
const Container = memo(function Container(props: PropsWithChildren) {
|
||||
const mobileMenuOpen = useMenuMobileOpen()
|
||||
|
||||
return (
|
||||
<div
|
||||
// #docs-content-container is used by layout to scroll to top
|
||||
id="docs-content-container"
|
||||
className={[
|
||||
// 'overflow-x-auto',
|
||||
'w-full transition-all ease-out',
|
||||
// 'absolute lg:relative',
|
||||
mobileMenuOpen ? 'ml-[75%] sm:ml-[50%] md:ml-[33%] overflow-hidden' : 'overflow-auto',
|
||||
// desktop override any margin styles
|
||||
'lg:ml-0',
|
||||
].join(' ')}
|
||||
>
|
||||
<div className="flex flex-col relative">{props.children}</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
const NavContainer = memo(function NavContainer() {
|
||||
const mobileMenuOpen = useMenuMobileOpen()
|
||||
|
||||
return (
|
||||
<nav
|
||||
aria-labelledby="main-nav-title"
|
||||
className={[
|
||||
// 'hidden',
|
||||
'absolute lg:relative',
|
||||
mobileMenuOpen ? 'w-[75%] sm:w-[50%] md:w-[33%] left-0' : 'w-0 -left-[280px]',
|
||||
'lg:w-[420px] !lg:left-0',
|
||||
// desktop override any left styles
|
||||
'lg:left-0',
|
||||
'transition-all',
|
||||
'top-0',
|
||||
'flex flex-col ml-0',
|
||||
].join(' ')}
|
||||
>
|
||||
<div
|
||||
className={[
|
||||
'top-0',
|
||||
'relative',
|
||||
'w-auto',
|
||||
'border-r overflow-auto h-screen',
|
||||
'backdrop-blur backdrop-filter bg-background',
|
||||
'flex flex-col',
|
||||
].join(' ')}
|
||||
>
|
||||
<h1 id="main-nav-title" className="sr-only">
|
||||
Main menu
|
||||
</h1>
|
||||
<div className="top-0 sticky z-10">
|
||||
<div>
|
||||
<div>
|
||||
<div
|
||||
className={[
|
||||
'hidden lg:flex lg:height-auto',
|
||||
'pt-8 bg-background flex-col gap-8',
|
||||
].join(' ')}
|
||||
>
|
||||
<HeaderLogo />
|
||||
</div>
|
||||
<div className="h-4 bg-background w-full"></div>
|
||||
<div className="bg-gradient-to-b from-background to-transparent h-4 w-full"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={[
|
||||
'transition-all ease-out duration-200',
|
||||
'absolute left-0 right-0 h-screen',
|
||||
'px-5 pl-5 py-16',
|
||||
'top-[0px]',
|
||||
'bg-background',
|
||||
// desktop styles
|
||||
'lg:relative lg:top-0 lg:left-0 lg:pb-10 lg:px-10 lg:pt-0 lg:flex',
|
||||
'lg:opacity-100 lg:visible',
|
||||
].join(' ')}
|
||||
>
|
||||
<NavigationMenu />
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
)
|
||||
})
|
||||
import { PropsWithChildren } from 'react'
|
||||
|
||||
const SiteLayout = ({ children }: PropsWithChildren<{}>) => {
|
||||
return (
|
||||
@@ -351,32 +7,7 @@ const SiteLayout = ({ children }: PropsWithChildren<{}>) => {
|
||||
<Head>
|
||||
<title>Supabase Docs</title>
|
||||
</Head>
|
||||
<main className="grow overflow-hidden">
|
||||
<div className="flex flex-row h-full">
|
||||
<NavContainer />
|
||||
<Container>
|
||||
<div className={['lg:sticky top-0 z-10 overflow-hidden'].join(' ')}>
|
||||
<TopNavBar />
|
||||
</div>
|
||||
<div
|
||||
className={[
|
||||
'sticky transition-all top-0',
|
||||
'z-10',
|
||||
'backdrop-blur backdrop-filter bg-background',
|
||||
].join(' ')}
|
||||
>
|
||||
<div className={['lg:hidden', 'px-5 ', 'border-b z-10'].join(' ')}>
|
||||
<MobileHeader />
|
||||
</div>
|
||||
</div>
|
||||
<div className="grow">
|
||||
{children}
|
||||
<Footer />
|
||||
</div>
|
||||
<MobileMenuBackdrop />
|
||||
</Container>
|
||||
</div>
|
||||
</main>
|
||||
<main className="grow overflow-hidden">{children}</main>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -10,8 +10,10 @@ import components from '~/components'
|
||||
import { highlightSelectedTocItem } from '~/components/CustomHTMLElements/CustomHTMLElements.utils'
|
||||
import { FooterHelpCalloutType } from '~/components/FooterHelpCallout'
|
||||
import GuidesTableOfContents from '~/components/GuidesTableOfContents'
|
||||
import { type MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import useHash from '~/hooks/useHash'
|
||||
import { LayoutMainContent } from '../DefaultLayout'
|
||||
import { MainSkeleton } from '../MainSkeleton'
|
||||
|
||||
interface Props {
|
||||
meta: {
|
||||
@@ -30,6 +32,7 @@ interface Props {
|
||||
toc?: any
|
||||
currentPage?: string
|
||||
hideToc?: boolean
|
||||
menuId: MenuId
|
||||
}
|
||||
|
||||
const Layout: FC<Props> = (props) => {
|
||||
@@ -42,6 +45,8 @@ const Layout: FC<Props> = (props) => {
|
||||
const { asPath } = useRouter()
|
||||
const router = useRouter()
|
||||
|
||||
const menuId = props.menuId
|
||||
|
||||
const EDIT_BUTTON_EXCLUDE_LIST = ['/404']
|
||||
|
||||
useEffect(() => {
|
||||
@@ -108,77 +113,79 @@ const Layout: FC<Props> = (props) => {
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<LayoutMainContent className="pb-0">
|
||||
<div className={['grid grid-cols-12 relative gap-4'].join(' ')}>
|
||||
<div
|
||||
className={[
|
||||
'relative',
|
||||
!props.hideToc ? 'col-span-12 md:col-span-9' : 'col-span-12',
|
||||
'transition-all ease-out',
|
||||
'duration-100',
|
||||
].join(' ')}
|
||||
>
|
||||
{props.meta?.breadcrumb && (
|
||||
<p className="text-brand tracking-wider mb-3">{props.meta.breadcrumb}</p>
|
||||
)}
|
||||
<article
|
||||
ref={articleRef}
|
||||
className={`${
|
||||
props.meta?.hide_table_of_contents || !hasTableOfContents ? '' : ''
|
||||
} prose max-w-none`}
|
||||
>
|
||||
<h1 className="mb-0">{props.meta.title}</h1>
|
||||
{props.meta?.subtitle && (
|
||||
<h2 className="mt-3 text-xl text-foreground-light">{props.meta.subtitle}</h2>
|
||||
)}
|
||||
<div className="w-full border-b my-8"></div>
|
||||
<MDXProvider components={components}>{props.children}</MDXProvider>
|
||||
|
||||
{EDIT_BUTTON_EXCLUDE_LIST.includes(router.route) ? (
|
||||
<></>
|
||||
) : (
|
||||
<div className="mt-16 not-prose">
|
||||
<div>
|
||||
<a
|
||||
href={`https://github.com/${
|
||||
props.editLink ||
|
||||
`supabase/supabase/edit/master/apps/docs/pages${router.asPath}.mdx`
|
||||
}
|
||||
`}
|
||||
className="text-sm transition flex items-center gap-1 text-scale-1000 hover:text-scale-1200 w-fit"
|
||||
>
|
||||
Edit this page on GitHub <IconExternalLink size={14} strokeWidth={1.5} />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</article>
|
||||
</div>
|
||||
{!props.hideToc && hasTableOfContents && !props.meta?.hide_table_of_contents && (
|
||||
<MainSkeleton menuId={menuId}>
|
||||
<LayoutMainContent className="pb-0">
|
||||
<div className={['grid grid-cols-12 relative gap-4'].join(' ')}>
|
||||
<div
|
||||
className={[
|
||||
'col-span-3',
|
||||
'border-overlay bg-background table-of-contents-height',
|
||||
'thin-scrollbar overflow-y-auto sticky hidden md:block md:col-span-3 px-2',
|
||||
'relative',
|
||||
!props.hideToc ? 'col-span-12 md:col-span-9' : 'col-span-12',
|
||||
'transition-all ease-out',
|
||||
'duration-100',
|
||||
].join(' ')}
|
||||
>
|
||||
<div className="border-l">
|
||||
{props.meta?.tocVideo && !!tocVideoPreview && (
|
||||
<div className="relative mb-6 pl-5">
|
||||
<ExpandableVideo imgUrl={tocVideoPreview} videoId={props.meta.tocVideo} />
|
||||
{props.meta?.breadcrumb && (
|
||||
<p className="text-brand tracking-wider mb-3">{props.meta.breadcrumb}</p>
|
||||
)}
|
||||
<article
|
||||
ref={articleRef}
|
||||
className={`${
|
||||
props.meta?.hide_table_of_contents || !hasTableOfContents ? '' : ''
|
||||
} prose max-w-none`}
|
||||
>
|
||||
<h1 className="mb-0">{props.meta.title}</h1>
|
||||
{props.meta?.subtitle && (
|
||||
<h2 className="mt-3 text-xl text-foreground-light">{props.meta.subtitle}</h2>
|
||||
)}
|
||||
<div className="w-full border-b my-8"></div>
|
||||
<MDXProvider components={components}>{props.children}</MDXProvider>
|
||||
|
||||
{EDIT_BUTTON_EXCLUDE_LIST.includes(router.route) ? (
|
||||
<></>
|
||||
) : (
|
||||
<div className="mt-16 not-prose">
|
||||
<div>
|
||||
<a
|
||||
href={`https://github.com/${
|
||||
props.editLink ||
|
||||
`supabase/supabase/edit/master/apps/docs/pages${router.asPath}.mdx`
|
||||
}
|
||||
`}
|
||||
className="text-sm transition flex items-center gap-1 text-scale-1000 hover:text-scale-1200 w-fit"
|
||||
>
|
||||
Edit this page on GitHub <IconExternalLink size={14} strokeWidth={1.5} />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<span className="block font-mono text-xs uppercase text-foreground px-5 mb-6">
|
||||
On this page
|
||||
</span>
|
||||
<GuidesTableOfContents list={tocList} />
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</LayoutMainContent>
|
||||
{!props.hideToc && hasTableOfContents && !props.meta?.hide_table_of_contents && (
|
||||
<div
|
||||
className={[
|
||||
'col-span-3',
|
||||
'border-overlay bg-background table-of-contents-height',
|
||||
'thin-scrollbar overflow-y-auto sticky hidden md:block md:col-span-3 px-2',
|
||||
'transition-all ease-out',
|
||||
'duration-100',
|
||||
].join(' ')}
|
||||
>
|
||||
<div className="border-l">
|
||||
{props.meta?.tocVideo && !!tocVideoPreview && (
|
||||
<div className="relative mb-6 pl-5">
|
||||
<ExpandableVideo imgUrl={tocVideoPreview} videoId={props.meta.tocVideo} />
|
||||
</div>
|
||||
)}
|
||||
<span className="block font-mono text-xs uppercase text-foreground px-5 mb-6">
|
||||
On this page
|
||||
</span>
|
||||
<GuidesTableOfContents list={tocList} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</LayoutMainContent>
|
||||
</MainSkeleton>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ const nextConfig = {
|
||||
'mdx-mermaid',
|
||||
'dayjs',
|
||||
'shared-data',
|
||||
'icons',
|
||||
],
|
||||
async headers() {
|
||||
return [
|
||||
|
||||
@@ -68,6 +68,7 @@
|
||||
"remark-gfm": "^3.0.1",
|
||||
"shared-data": "*",
|
||||
"ui": "*",
|
||||
"icons": "*",
|
||||
"ui-patterns": "*",
|
||||
"unist-builder": "^3.0.1",
|
||||
"unist-util-filter": "^4.0.1",
|
||||
@@ -90,7 +91,7 @@
|
||||
"jest-environment-jsdom": "^29.7.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"openapi-types": "^12.0.2",
|
||||
"openapi-typescript": "^6.7.2",
|
||||
"openapi-typescript": "^6.7.4",
|
||||
"tsconfig": "*",
|
||||
"tsx": "^4.6.2",
|
||||
"typescript": "^5.2.2"
|
||||
|
||||
@@ -14,7 +14,6 @@ import { CommandMenuProvider, PortalToast, TabsProvider } from 'ui'
|
||||
import { useConsent } from 'ui-patterns/ConsentToast'
|
||||
|
||||
import Favicons from '~/components/Favicons'
|
||||
import { IPv4DeprecationBanner } from '~/components/IPv4DeprecationBanner'
|
||||
import SiteLayout from '~/layouts/SiteLayout'
|
||||
import { IS_PLATFORM, IS_PREVIEW } from '~/lib/constants'
|
||||
import { unauthedAllowedPost } from '~/lib/fetch/fetchWrappers'
|
||||
@@ -223,7 +222,6 @@ function MyApp({ Component, pageProps }: AppPropsWithLayout) {
|
||||
<CommandMenuProvider site="docs">
|
||||
<TabsProvider>
|
||||
<div className="h-screen flex flex-col">
|
||||
<IPv4DeprecationBanner />
|
||||
<SiteLayout>
|
||||
<PortalToast />
|
||||
<Component {...pageProps} />
|
||||
|
||||
@@ -2,6 +2,7 @@ import { type GetStaticPaths, type GetStaticProps, type InferGetStaticPropsType
|
||||
import { MDXRemote } from 'next-mdx-remote'
|
||||
|
||||
import components from '~/components'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
import { getGuidesStaticPaths, getGuidesStaticProps } from '~/lib/docs'
|
||||
|
||||
@@ -21,7 +22,7 @@ export default function AiGuide({
|
||||
const { hideToc, ...meta } = frontmatter
|
||||
|
||||
return (
|
||||
<Layout meta={meta} hideToc={hideToc} editLink={editLink}>
|
||||
<Layout meta={meta} hideToc={hideToc} editLink={editLink} menuId={MenuId.Ai}>
|
||||
<MDXRemote {...mdxSource} components={components} />
|
||||
</Layout>
|
||||
)
|
||||
|
||||
@@ -11,6 +11,7 @@ import Layout from '~/layouts/DefaultGuideLayout'
|
||||
import { UrlTransformFunction, linkTransform } from '~/lib/mdx/plugins/rehypeLinkTransform'
|
||||
import remarkMkDocsAdmonition from '~/lib/mdx/plugins/remarkAdmonition'
|
||||
import { removeTitle } from '~/lib/mdx/plugins/remarkRemoveTitle'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
|
||||
// We fetch these docs at build time from an external repo
|
||||
const org = 'supabase'
|
||||
@@ -61,7 +62,7 @@ interface PythonClientDocsProps {
|
||||
|
||||
export default function PythonClientDocs({ source, meta }: PythonClientDocsProps) {
|
||||
return (
|
||||
<Layout meta={meta}>
|
||||
<Layout meta={meta} menuId={MenuId.Ai}>
|
||||
<MDXRemote {...source} components={components} />
|
||||
</Layout>
|
||||
)
|
||||
|
||||
@@ -2,6 +2,7 @@ import { type GetStaticPaths, type GetStaticProps, type InferGetStaticPropsType
|
||||
import { MDXRemote } from 'next-mdx-remote'
|
||||
|
||||
import components from '~/components'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
import { getGuidesStaticPaths, getGuidesStaticProps } from '~/lib/docs'
|
||||
|
||||
@@ -21,7 +22,7 @@ export default function ApiGuide({
|
||||
const { hideToc, ...meta } = frontmatter
|
||||
|
||||
return (
|
||||
<Layout meta={meta} hideToc={hideToc} editLink={editLink}>
|
||||
<Layout meta={meta} hideToc={hideToc} editLink={editLink} menuId={MenuId.Api}>
|
||||
<MDXRemote {...mdxSource} components={components} />
|
||||
</Layout>
|
||||
)
|
||||
|
||||
@@ -2,6 +2,7 @@ import { type GetStaticPaths, type GetStaticProps, type InferGetStaticPropsType
|
||||
import { MDXRemote } from 'next-mdx-remote'
|
||||
|
||||
import components from '~/components'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
import { getGuidesStaticPaths, getGuidesStaticProps } from '~/lib/docs'
|
||||
|
||||
@@ -21,7 +22,7 @@ export default function AuthGuide({
|
||||
const { hideToc, ...meta } = frontmatter
|
||||
|
||||
return (
|
||||
<Layout meta={meta} hideToc={hideToc} editLink={editLink}>
|
||||
<Layout meta={meta} hideToc={hideToc} editLink={editLink} menuId={MenuId.Auth}>
|
||||
<MDXRemote {...mdxSource} components={components} />
|
||||
</Layout>
|
||||
)
|
||||
|
||||
@@ -2,6 +2,7 @@ import { type GetStaticPaths, type GetStaticProps, type InferGetStaticPropsType
|
||||
import { MDXRemote } from 'next-mdx-remote'
|
||||
|
||||
import components from '~/components'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
import { getGuidesStaticPaths, getGuidesStaticProps } from '~/lib/docs'
|
||||
|
||||
@@ -21,7 +22,7 @@ export default function CliGuide({
|
||||
const { hideToc, ...meta } = frontmatter
|
||||
|
||||
return (
|
||||
<Layout meta={meta} hideToc={hideToc} editLink={editLink}>
|
||||
<Layout meta={meta} hideToc={hideToc} editLink={editLink} menuId={MenuId.Cli}>
|
||||
<MDXRemote {...mdxSource} components={components} />
|
||||
</Layout>
|
||||
)
|
||||
|
||||
@@ -5,6 +5,8 @@ import GuidesTableOfContents from '~/components/GuidesTableOfContents'
|
||||
import { Heading } from '~/components/CustomHTMLElements'
|
||||
import Head from 'next/head'
|
||||
import { CodeBlock } from 'ui'
|
||||
import { MainSkeleton } from '~/layouts/MainSkeleton'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
|
||||
// Parameters are grouped on the page by tag
|
||||
const tocList = []
|
||||
@@ -29,24 +31,26 @@ export default function Config() {
|
||||
<Head>
|
||||
<title>Supabase CLI config</title>
|
||||
</Head>
|
||||
<div className="grid grid-cols-12 relative gap-4 px-5 max-w-7xl mx-auto py-16">
|
||||
<div className="relative col-span-12 md:col-span-9 transition-all ease-out duration-100">
|
||||
<div className="w-full prose">
|
||||
<h1>CLI configuration</h1>
|
||||
<div className="max-w-xs w-32 h-[1px] bg-gradient-to-r from-brand-300 to-brand my-8"></div>
|
||||
<ReactMarkdown>{specFile.info.description}</ReactMarkdown>
|
||||
<div>{content}</div>
|
||||
<MainSkeleton menuId={MenuId.Cli}>
|
||||
<div className="grid grid-cols-12 relative gap-4 px-5 max-w-7xl mx-auto py-16">
|
||||
<div className="relative col-span-12 md:col-span-9 transition-all ease-out duration-100">
|
||||
<div className="w-full prose">
|
||||
<h1>CLI configuration</h1>
|
||||
<div className="max-w-xs w-32 h-[1px] bg-gradient-to-r from-brand-300 to-brand my-8"></div>
|
||||
<ReactMarkdown>{specFile.info.description}</ReactMarkdown>
|
||||
<div>{content}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="md:col-span-3">
|
||||
<div className="sticky overflow-auto max-h-[calc(100vh-60px-5rem)] pb-3 top-32 border-l">
|
||||
<span className="block font-mono text-xs uppercase text-foreground pl-5 mb-4">
|
||||
On this page
|
||||
</span>
|
||||
<GuidesTableOfContents list={tocList} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="md:col-span-3">
|
||||
<div className="sticky overflow-auto max-h-[calc(100vh-60px-5rem)] pb-3 top-32 border-l">
|
||||
<span className="block font-mono text-xs uppercase text-foreground pl-5 mb-4">
|
||||
On this page
|
||||
</span>
|
||||
<GuidesTableOfContents list={tocList} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</MainSkeleton>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import { UrlTransformFunction, linkTransform } from '~/lib/mdx/plugins/rehypeLin
|
||||
import remarkMkDocsAdmonition from '~/lib/mdx/plugins/remarkAdmonition'
|
||||
import { removeTitle } from '~/lib/mdx/plugins/remarkRemoveTitle'
|
||||
import remarkPyMdownTabs from '~/lib/mdx/plugins/remarkTabs'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
|
||||
// We fetch these docs at build time from an external repo
|
||||
const org = 'supabase'
|
||||
@@ -62,7 +63,7 @@ interface ActionDocsProps {
|
||||
|
||||
export default function ActionDocs({ source, meta }: ActionDocsProps) {
|
||||
return (
|
||||
<Layout meta={meta}>
|
||||
<Layout meta={meta} menuId={MenuId.Cli}>
|
||||
<MDXRemote {...source} components={components} />
|
||||
</Layout>
|
||||
)
|
||||
|
||||
@@ -2,6 +2,7 @@ import { type GetStaticPaths, type GetStaticProps, type InferGetStaticPropsType
|
||||
import { MDXRemote } from 'next-mdx-remote'
|
||||
|
||||
import components from '~/components'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
import { getGuidesStaticPaths, getGuidesStaticProps } from '~/lib/docs'
|
||||
|
||||
@@ -31,7 +32,7 @@ export default function DatabaseGuide({
|
||||
const { hideToc, ...meta } = frontmatter
|
||||
|
||||
return (
|
||||
<Layout meta={meta} hideToc={hideToc} editLink={editLink}>
|
||||
<Layout meta={meta} hideToc={hideToc} editLink={editLink} menuId={MenuId.Database}>
|
||||
<MDXRemote {...mdxSource} components={components} />
|
||||
</Layout>
|
||||
)
|
||||
|
||||
@@ -10,6 +10,7 @@ import remarkGfm from 'remark-gfm'
|
||||
import codeHikeTheme from 'config/code-hike.theme.json' assert { type: 'json' }
|
||||
|
||||
import components from '~/components'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
import { getGuidesStaticPaths, getGuidesStaticProps } from '~/lib/docs'
|
||||
import { UrlTransformFunction, linkTransform } from '~/lib/mdx/plugins/rehypeLinkTransform'
|
||||
@@ -83,7 +84,7 @@ export default function WrappersDocs({
|
||||
editLink,
|
||||
}: InferGetStaticPropsType<typeof getStaticProps>) {
|
||||
return (
|
||||
<Layout meta={meta} editLink={editLink}>
|
||||
<Layout meta={meta} editLink={editLink} menuId={MenuId.Database}>
|
||||
<MDXRemote {...source} components={components} />
|
||||
</Layout>
|
||||
)
|
||||
|
||||
@@ -2,6 +2,7 @@ import { type GetStaticPaths, type GetStaticProps, type InferGetStaticPropsType
|
||||
import { MDXRemote } from 'next-mdx-remote'
|
||||
|
||||
import components from '~/components'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
import { getGuidesStaticPaths, getGuidesStaticProps } from '~/lib/docs'
|
||||
|
||||
@@ -21,7 +22,7 @@ export default function FunctionsGuide({
|
||||
const { hideToc, ...meta } = frontmatter
|
||||
|
||||
return (
|
||||
<Layout meta={meta} hideToc={hideToc} editLink={editLink}>
|
||||
<Layout meta={meta} hideToc={hideToc} editLink={editLink} menuId={MenuId.Functions}>
|
||||
<MDXRemote {...mdxSource} components={components} />
|
||||
</Layout>
|
||||
)
|
||||
|
||||
@@ -2,6 +2,7 @@ import { type GetStaticPaths, type GetStaticProps, type InferGetStaticPropsType
|
||||
import { MDXRemote } from 'next-mdx-remote'
|
||||
|
||||
import components from '~/components'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
import { getGuidesStaticPaths, getGuidesStaticProps } from '~/lib/docs'
|
||||
|
||||
@@ -21,7 +22,7 @@ export default function GettingStartedGuide({
|
||||
const { hideToc, ...meta } = frontmatter
|
||||
|
||||
return (
|
||||
<Layout meta={meta} hideToc={hideToc} editLink={editLink}>
|
||||
<Layout meta={meta} hideToc={hideToc} editLink={editLink} menuId={MenuId.GettingStarted}>
|
||||
<MDXRemote {...mdxSource} components={components} />
|
||||
</Layout>
|
||||
)
|
||||
|
||||
@@ -5,14 +5,17 @@ import { serialize } from 'next-mdx-remote/serialize'
|
||||
import { isAbsolute, relative } from 'path'
|
||||
import rehypeSlug from 'rehype-slug'
|
||||
import remarkGfm from 'remark-gfm'
|
||||
import codeHikeTheme from 'config/code-hike.theme.json' assert { type: 'json' }
|
||||
|
||||
import components from '~/components'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
import { UrlTransformFunction, linkTransform } 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 codeHikeTheme from 'config/code-hike.theme.json' assert { type: 'json' }
|
||||
|
||||
// We fetch these docs at build time from an external repo
|
||||
const org = 'supabase'
|
||||
const repo = 'pg_graphql'
|
||||
@@ -114,7 +117,7 @@ interface PGGraphQLDocsProps {
|
||||
|
||||
export default function PGGraphQLDocs({ source, meta }: PGGraphQLDocsProps) {
|
||||
return (
|
||||
<Layout meta={meta}>
|
||||
<Layout meta={meta} menuId={MenuId.Graphql}>
|
||||
<MDXRemote {...source} components={components} />
|
||||
</Layout>
|
||||
)
|
||||
|
||||
@@ -2,6 +2,7 @@ import { type GetStaticPaths, type GetStaticProps, type InferGetStaticPropsType
|
||||
import { MDXRemote } from 'next-mdx-remote'
|
||||
|
||||
import components from '~/components'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
import { getGuidesStaticPaths, getGuidesStaticProps } from '~/lib/docs'
|
||||
|
||||
@@ -21,7 +22,7 @@ export default function PlatformGuide({
|
||||
const { hideToc, ...meta } = frontmatter
|
||||
|
||||
return (
|
||||
<Layout meta={meta} hideToc={hideToc} editLink={editLink}>
|
||||
<Layout meta={meta} hideToc={hideToc} editLink={editLink} menuId={MenuId.Platform}>
|
||||
<MDXRemote {...mdxSource} components={components} />
|
||||
</Layout>
|
||||
)
|
||||
|
||||
@@ -2,6 +2,7 @@ import { type GetStaticPaths, type GetStaticProps, type InferGetStaticPropsType
|
||||
import { MDXRemote } from 'next-mdx-remote'
|
||||
|
||||
import components from '~/components'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
import { getGuidesStaticPaths, getGuidesStaticProps } from '~/lib/docs'
|
||||
|
||||
@@ -21,7 +22,7 @@ export default function RealtimeGuide({
|
||||
const { hideToc, ...meta } = frontmatter
|
||||
|
||||
return (
|
||||
<Layout meta={meta} hideToc={hideToc} editLink={editLink}>
|
||||
<Layout meta={meta} hideToc={hideToc} editLink={editLink} menuId={MenuId.Realtime}>
|
||||
<MDXRemote {...mdxSource} components={components} />
|
||||
</Layout>
|
||||
)
|
||||
|
||||
@@ -2,6 +2,7 @@ import { type GetStaticPaths, type GetStaticProps, type InferGetStaticPropsType
|
||||
import { MDXRemote } from 'next-mdx-remote'
|
||||
|
||||
import components from '~/components'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
import { getGuidesStaticPaths, getGuidesStaticProps } from '~/lib/docs'
|
||||
|
||||
@@ -21,7 +22,7 @@ export default function ResourcesGuide({
|
||||
const { hideToc, ...meta } = frontmatter
|
||||
|
||||
return (
|
||||
<Layout meta={meta} hideToc={hideToc} editLink={editLink}>
|
||||
<Layout meta={meta} hideToc={hideToc} editLink={editLink} menuId={MenuId.Resources}>
|
||||
<MDXRemote {...mdxSource} components={components} />
|
||||
</Layout>
|
||||
)
|
||||
|
||||
@@ -2,6 +2,7 @@ import { type GetStaticPaths, type GetStaticProps, type InferGetStaticPropsType
|
||||
import { MDXRemote } from 'next-mdx-remote'
|
||||
|
||||
import components from '~/components'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
import { getGuidesStaticPaths, getGuidesStaticProps } from '~/lib/docs'
|
||||
|
||||
@@ -21,7 +22,7 @@ export default function SelfHostingGuide({
|
||||
const { hideToc, ...meta } = frontmatter
|
||||
|
||||
return (
|
||||
<Layout meta={meta} hideToc={hideToc} editLink={editLink}>
|
||||
<Layout meta={meta} hideToc={hideToc} editLink={editLink} menuId={MenuId.SelfHosting}>
|
||||
<MDXRemote {...mdxSource} components={components} />
|
||||
</Layout>
|
||||
)
|
||||
|
||||
@@ -3,6 +3,7 @@ import { MDXRemote } from 'next-mdx-remote'
|
||||
import { serialize } from 'next-mdx-remote/serialize'
|
||||
|
||||
import components from '~/components'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import Param from '~/components/Params'
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
import { getAnalyticsConfigV0 } from '~/lib/mdx/getConfig'
|
||||
@@ -27,6 +28,7 @@ export const Page = (props: InferGetStaticPropsType<typeof getStaticProps>) => (
|
||||
<Layout
|
||||
meta={meta}
|
||||
editLink="/supabase/supabase/blob/master/apps/docs/pages/guides/self-hosting/analytics/config.tsx"
|
||||
menuId={MenuId.SelfHosting}
|
||||
>
|
||||
<MDXRemote {...props.descriptionSource} components={components} />
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { MDXRemote } from 'next-mdx-remote'
|
||||
import { serialize } from 'next-mdx-remote/serialize'
|
||||
|
||||
import components from '~/components'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import Param from '~/components/Params'
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
import { getAuthConfigV1 } from '~/lib/mdx/getConfig'
|
||||
@@ -27,6 +28,7 @@ export const Page = (props: InferGetStaticPropsType<typeof getStaticProps>) => (
|
||||
<Layout
|
||||
meta={meta}
|
||||
editLink="/supabase/supabase/blob/master/apps/docs/pages/guides/self-hosting/analytics/config.tsx"
|
||||
menuId={MenuId.SelfHosting}
|
||||
>
|
||||
<MDXRemote {...props.descriptionSource} components={components} />
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { MDXRemote } from 'next-mdx-remote'
|
||||
import { serialize } from 'next-mdx-remote/serialize'
|
||||
|
||||
import components from '~/components'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import Param from '~/components/Params'
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
import { getRealtimeConfigV0 } from '~/lib/mdx/getConfig'
|
||||
@@ -27,6 +28,7 @@ export const Page = (props: InferGetStaticPropsType<typeof getStaticProps>) => (
|
||||
<Layout
|
||||
meta={meta}
|
||||
editLink="/supabase/supabase/blob/master/apps/docs/pages/guides/self-hosting/analytics/config.tsx"
|
||||
menuId={MenuId.SelfHosting}
|
||||
>
|
||||
<MDXRemote {...props.descriptionSource} components={components} />
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { MDXRemote } from 'next-mdx-remote'
|
||||
import { serialize } from 'next-mdx-remote/serialize'
|
||||
|
||||
import components from '~/components'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import Param from '~/components/Params'
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
import { getStorageConfigV0 } from '~/lib/mdx/getConfig'
|
||||
@@ -27,6 +28,7 @@ export const Page = (props: InferGetStaticPropsType<typeof getStaticProps>) => (
|
||||
<Layout
|
||||
meta={meta}
|
||||
editLink="/supabase/supabase/blob/master/apps/docs/pages/guides/self-hosting/analytics/config.tsx"
|
||||
menuId={MenuId.SelfHosting}
|
||||
>
|
||||
<MDXRemote {...props.descriptionSource} components={components} />
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { type GetStaticPaths, type GetStaticProps, type InferGetStaticPropsType
|
||||
import { MDXRemote } from 'next-mdx-remote'
|
||||
|
||||
import components from '~/components'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
import { getGuidesStaticPaths, getGuidesStaticProps } from '~/lib/docs'
|
||||
|
||||
@@ -21,7 +22,7 @@ export default function StorageGuide({
|
||||
const { hideToc, ...meta } = frontmatter
|
||||
|
||||
return (
|
||||
<Layout meta={meta} hideToc={hideToc} editLink={editLink}>
|
||||
<Layout meta={meta} hideToc={hideToc} editLink={editLink} menuId={MenuId.Storage}>
|
||||
<MDXRemote {...mdxSource} components={components} />
|
||||
</Layout>
|
||||
)
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
|
||||
export const meta = {
|
||||
id: 'contributing',
|
||||
title: 'Contributing',
|
||||
description: 'Want to help?',
|
||||
}
|
||||
|
||||
## How to contribute
|
||||
|
||||
Supabase has many [open source repos](https://github.com/orgs/supabase/repositories). Some of the more popular ones are:
|
||||
|
||||
- [Supabase](https://github.com/supabase/supabase) - Our Dashboard, Websites, and example apps
|
||||
- [Supabase-js](https://github.com/supabase/supabase-js) - A client-side library written in TypeScript
|
||||
- [Gotrue](https://github.com/supabase/gotrue) - Our auth server, written in Go
|
||||
- [Realtime](https://github.com/supabase/realtime) - A server for streaming changes from Postgres, written in Elixir
|
||||
- [browse all](https://github.com/orgs/supabase/repositories)
|
||||
|
||||
Want to contribute? Why not jump into our GitHub repo and:
|
||||
|
||||
- [Sponsor Supabase](https://github.com/sponsors/supabase).
|
||||
- [Answer Discussions](https://github.com/supabase/supabase/discussions).
|
||||
- Submit an issue to one of our [repos](https://github.com/orgs/supabase/repositories)
|
||||
- Report a performance issue or a part of the documentation that you find confusing.
|
||||
- Create a pull request in one of our [repos](https://github.com/orgs/supabase/repositories)
|
||||
- [Translate our Readme](https://github.com/supabase/supabase/issues/1341).
|
||||
- Try our products and give feedback.
|
||||
- Spread the word if you like what we are doing.
|
||||
|
||||
export const Page = ({ children }) => <Layout meta={meta} children={children} />
|
||||
|
||||
export default Page
|
||||
@@ -1,21 +0,0 @@
|
||||
import Layout from '~/layouts/DefaultGuideLayout'
|
||||
|
||||
export const meta = {
|
||||
id: 'introduction',
|
||||
title: 'Supabase Handbook',
|
||||
description: 'The Supabase public handbook and manifesto',
|
||||
}
|
||||
|
||||
Supabase is thinking in public. Everything is online, no matter how raw the current state of things.
|
||||
|
||||
This is our public handbook and manifesto. We are completely opensource and this means that you, our users, are also our team members.
|
||||
|
||||
---
|
||||
|
||||
## Opensource
|
||||
|
||||
Wherever we can we will support existing opensource tools and libraries.
|
||||
|
||||
export const Page = ({ children }) => <Layout meta={meta} children={children} />
|
||||
|
||||
export default Page
|
||||
@@ -1,168 +0,0 @@
|
||||
import specFile from '~/spec/transforms/analytics_v0_openapi_deparsed.json' assert { type: 'json' }
|
||||
import { gen_v3, enrichedOperation } from '~/lib/refGenerator/helpers'
|
||||
import { Tabs, CodeBlock } from 'ui'
|
||||
|
||||
import RefSubLayout from '~/layouts/ref/RefSubLayout'
|
||||
|
||||
export type AcceptedValue = {
|
||||
id: string
|
||||
name: string
|
||||
type: 'string' | 'boolean' | 'object'
|
||||
description?: string
|
||||
}
|
||||
|
||||
export type Flag = {
|
||||
id: string
|
||||
name: string
|
||||
description: string
|
||||
default_value: string
|
||||
accepted_values: AcceptedValue[]
|
||||
}
|
||||
|
||||
export type ApiParameter = {
|
||||
example: string
|
||||
in: string
|
||||
name: string
|
||||
required: boolean
|
||||
schema: {
|
||||
type: string
|
||||
example: string
|
||||
}
|
||||
}
|
||||
// @ts-ignore
|
||||
const generatedSpec = gen_v3(specFile, 'wat', { apiUrl: 'apiv0' })
|
||||
|
||||
export default function Config() {
|
||||
return (
|
||||
<RefSubLayout>
|
||||
<div className="flex my-16">
|
||||
<div className="w-full">
|
||||
<div className="grid gap-16">
|
||||
<h1 className="text-4xl uppercase">{generatedSpec.info.title}</h1>
|
||||
<p>{generatedSpec.info.description}</p>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-32 mx-auto max-w-5xl mt-24">
|
||||
{generatedSpec.operations.map((operation: any) => (
|
||||
<div className="border-b pb-8">
|
||||
<RefSubLayout.Section
|
||||
slug={operation.id}
|
||||
title={operation.summary}
|
||||
id={operation.operationId}
|
||||
monoFont={false}
|
||||
>
|
||||
<RefSubLayout.Details>
|
||||
<div className="mt-4">
|
||||
<code className="text-md flex gap-4 text-md text-foreground-lighter break-all">
|
||||
<span className="uppercase whitespace-nowrap ">{operation.operation}</span>
|
||||
{operation.fullPath}
|
||||
</code>
|
||||
</div>
|
||||
{/* Path Parameters */}
|
||||
{operation.parameters &&
|
||||
operation.parameters.filter((parameter) => parameter.in === 'path').length >
|
||||
0 && (
|
||||
<div className="mt-12">
|
||||
<h2 className="border-b pb-2 text-xl">Path parameters</h2>
|
||||
<ul className="mt-4">
|
||||
{operation.parameters &&
|
||||
operation.parameters
|
||||
.filter((parameter: any) => parameter.in === 'path')
|
||||
.map((parameter: any) => (
|
||||
<li className="mt-8 border-b pb-6">
|
||||
<div>
|
||||
<div className="flex gap-4 items-center">
|
||||
<span className="font-bold">{parameter.name}</span>
|
||||
<div className="font-mono text-xs break-all">
|
||||
{parameter.required && (
|
||||
<div className="text-[10px] border border-amber-700 bg-amber-300 text-amber-900 px-2 tracking-wide font-mono py-0.25 rounded-full">
|
||||
REQUIRED
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<p className="mt-4">{parameter.description}</p>
|
||||
</div>
|
||||
{parameter.example && (
|
||||
<div className="mt-4 flex gap-4 items-center">
|
||||
<span>Example:</span>
|
||||
<span className="font-mono text-xs break-all">
|
||||
{parameter.example}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Header Parameters */}
|
||||
{operation.parameters &&
|
||||
operation.parameters.filter((parameter) => parameter.in === 'header').length >
|
||||
0 && (
|
||||
<div className="mt-12">
|
||||
<h2 className="border-b pb-2 text-xl">Header parameters</h2>
|
||||
<ul className="mt-4">
|
||||
{operation.parameters &&
|
||||
operation.parameters
|
||||
.filter((parameter: any) => parameter.in === 'header')
|
||||
.map((parameter: any) => (
|
||||
<li className="mt-8 border-b pb-6">
|
||||
<div className="flex gap-4 items-center">
|
||||
<span className="font-bold">{parameter.name}</span>
|
||||
<span className="font-mono text-xs break-all">
|
||||
{parameter.required && 'required'}
|
||||
</span>
|
||||
</div>
|
||||
<div className="mt-4 flex gap-4 items-center">
|
||||
<span>Example:</span>
|
||||
<span className="font-mono text-xs break-all">
|
||||
{parameter.example}
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
</RefSubLayout.Details>
|
||||
<RefSubLayout.Examples>
|
||||
{operation.responseList.length > 0 && (
|
||||
<>
|
||||
<h2 className="text-xl">Responses</h2>
|
||||
<Tabs
|
||||
scrollable
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId={
|
||||
operation.responseList[0].responseCode ??
|
||||
operation.responseList[0].responseCode
|
||||
}
|
||||
queryGroup="response-status"
|
||||
>
|
||||
{operation.responseList.map((response: any) => (
|
||||
<Tabs.Panel id={response.responseCode} label={response.responseCode}>
|
||||
<p>{response.description}</p>
|
||||
{response?.content && response?.content['application/json'] && (
|
||||
<div className="mt-8">
|
||||
<CodeBlock language="bash" className="relative">
|
||||
{JSON.stringify(response.content['application/json'], null, 2)}
|
||||
</CodeBlock>
|
||||
</div>
|
||||
)}
|
||||
</Tabs.Panel>
|
||||
))}
|
||||
</Tabs>
|
||||
</>
|
||||
)}
|
||||
</RefSubLayout.Examples>
|
||||
</RefSubLayout.Section>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</RefSubLayout>
|
||||
)
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
import fs from 'fs'
|
||||
import matter from 'gray-matter'
|
||||
import components from '~/components/index'
|
||||
import { MDXRemote } from 'next-mdx-remote'
|
||||
import { serialize } from 'next-mdx-remote/serialize'
|
||||
|
||||
import specFile from '~/spec/analytics_v0_config.yaml' assert { type: 'yml' }
|
||||
import { Parameter } from '~/lib/refGenerator/refTypes'
|
||||
|
||||
import ReactMarkdown from 'react-markdown'
|
||||
|
||||
// Parameters are grouped on the page by tag
|
||||
const TAGS = ['general', 'database']
|
||||
|
||||
export default function Config(props) {
|
||||
return (
|
||||
<div>
|
||||
<div className="flex my-16">
|
||||
<div className="w-full prose">
|
||||
<h1 className="text-4xl mb-16">{specFile.info.title} Configuration</h1>
|
||||
<ReactMarkdown>{specFile.info.description}</ReactMarkdown>
|
||||
<div>
|
||||
<div>
|
||||
{props.docs
|
||||
.filter((doc) => doc.introPage)
|
||||
.map((item) => (
|
||||
<MDXRemote {...item.content} components={components} />
|
||||
))}
|
||||
</div>
|
||||
{TAGS.map((tag) =>
|
||||
specFile.parameters
|
||||
.filter((param: Parameter) => param.tags[0] === tag)
|
||||
.map((parameter: Parameter, index) => (
|
||||
<div>
|
||||
{index === 0 && <h2 className="text-xl capitalize">{tag} Settings</h2>}
|
||||
<div className="mt-8">
|
||||
<div>
|
||||
<h2 className="text-xl font-medium text-foreground font-mono">
|
||||
<span className="mr-2">$</span>
|
||||
{parameter.title}
|
||||
</h2>
|
||||
<div className="grid" id={parameter.id}>
|
||||
<div className="border-b pb-8" key={parameter.id}>
|
||||
<div className=" mb-16">
|
||||
<p className="mb-4 scroll-mt-16 mt-0 text-foreground-light text-base">
|
||||
<ReactMarkdown>{parameter.description}</ReactMarkdown>
|
||||
</p>
|
||||
<div className="grid gap-2">
|
||||
<div className="flex gap-2">
|
||||
Required: <code>{parameter.required.toString()}</code>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
Default:
|
||||
<code>
|
||||
{parameter.default ? parameter.default.toString() : 'None'}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{parameter.links &&
|
||||
parameter.links.map((link) => (
|
||||
<div>
|
||||
<h3>See also:</h3>
|
||||
<li>
|
||||
<a href={link.link}>{link.name}</a>
|
||||
</li>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export async function getServerSideProps() {
|
||||
// an array of ids of the intro sections for this library
|
||||
const introPages = ['analytics']
|
||||
|
||||
const pages = [...introPages]
|
||||
|
||||
// Grab custom markdown intro page files
|
||||
const allMarkdownDocs = await Promise.all(
|
||||
pages.map(async (x: any, i) => {
|
||||
const pathName = `docs/ref/analytics/${x}.mdx`
|
||||
|
||||
const markdownExists = fs.existsSync(pathName)
|
||||
|
||||
const fileContents = markdownExists ? fs.readFileSync(pathName, 'utf8') : ''
|
||||
const { data, content } = matter(fileContents)
|
||||
|
||||
return {
|
||||
id: x,
|
||||
title: x,
|
||||
// ...content,
|
||||
meta: data,
|
||||
introPage: introPages.includes(x),
|
||||
content: content ? await serialize(content || '') : null,
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
return {
|
||||
props: {
|
||||
docs: allMarkdownDocs,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,28 @@
|
||||
import apiCommonSections from '~/spec/common-api-sections.json' assert { type: 'json' }
|
||||
import specFile from '~/spec/transforms/api_v0_openapi_deparsed.json' assert { type: 'json' }
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import RefSectionHandler from '~/components/reference/RefSectionHandler'
|
||||
import { flattenSections } from '~/lib/helpers'
|
||||
import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
|
||||
import { gen_v3 } from '~/lib/refGenerator/helpers'
|
||||
|
||||
import apiCommonSections from '~/spec/common-api-sections.json' assert { type: 'json' }
|
||||
import specFile from '~/spec/transforms/api_v0_openapi_deparsed.json' assert { type: 'json' }
|
||||
|
||||
// @ts-ignore
|
||||
const generatedSpec = gen_v3(specFile, 'wat', { apiUrl: 'apiv0' })
|
||||
const sections = flattenSections(apiCommonSections)
|
||||
const libraryPath = '/api'
|
||||
|
||||
export default function Config(props) {
|
||||
return <RefSectionHandler sections={sections} spec={generatedSpec} pageProps={props} type="api" />
|
||||
return (
|
||||
<RefSectionHandler
|
||||
menuId={MenuId.RefApi}
|
||||
sections={sections}
|
||||
spec={generatedSpec}
|
||||
pageProps={props}
|
||||
type="api"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export async function getStaticProps() {
|
||||
|
||||
@@ -1,168 +0,0 @@
|
||||
import { CodeBlock, Tabs } from 'ui'
|
||||
import specFile from '~/spec/transforms/auth_v1_openapi_deparsed.json' assert { type: 'json' }
|
||||
import { gen_v3 } from '~/lib/refGenerator/helpers'
|
||||
|
||||
import RefSubLayout from '~/layouts/ref/RefSubLayout'
|
||||
|
||||
export type AcceptedValue = {
|
||||
id: string
|
||||
name: string
|
||||
type: 'string' | 'boolean' | 'object'
|
||||
description?: string
|
||||
}
|
||||
|
||||
export type Flag = {
|
||||
id: string
|
||||
name: string
|
||||
description: string
|
||||
default_value: string
|
||||
accepted_values: AcceptedValue[]
|
||||
}
|
||||
|
||||
export type ApiParameter = {
|
||||
example: string
|
||||
in: string
|
||||
name: string
|
||||
required: boolean
|
||||
schema: {
|
||||
type: string
|
||||
example: string
|
||||
}
|
||||
}
|
||||
// @ts-ignore
|
||||
const generatedSpec = gen_v3(specFile, 'wat', { apiUrl: 'apiv0' })
|
||||
|
||||
export default function Config() {
|
||||
return (
|
||||
<RefSubLayout>
|
||||
<div className="flex my-16">
|
||||
<div className="w-full">
|
||||
<div className="grid gap-16">
|
||||
<h1 className="text-4xl uppercase">{generatedSpec.info.title}</h1>
|
||||
<p>{generatedSpec.info.description}</p>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-32 mx-auto max-w-5xl mt-24">
|
||||
{generatedSpec.operations.map((operation: any) => (
|
||||
<div className="border-b pb-8">
|
||||
<RefSubLayout.Section
|
||||
slug={operation.id}
|
||||
title={operation.summary}
|
||||
id={operation.operationId}
|
||||
monoFont={false}
|
||||
>
|
||||
<RefSubLayout.Details>
|
||||
<div className="mt-4">
|
||||
<code className="text-md flex gap-4 text-md text-foreground-lighter break-all">
|
||||
<span className="uppercase whitespace-nowrap ">{operation.operation}</span>
|
||||
{operation.fullPath}
|
||||
</code>
|
||||
</div>
|
||||
{/* Path Parameters */}
|
||||
{operation.parameters &&
|
||||
operation.parameters.filter((parameter) => parameter.in === 'path').length >
|
||||
0 && (
|
||||
<div className="mt-12">
|
||||
<h2 className="border-b pb-2 text-xl">Path parameters</h2>
|
||||
<ul className="mt-4">
|
||||
{operation.parameters &&
|
||||
operation.parameters
|
||||
.filter((parameter: any) => parameter.in === 'path')
|
||||
.map((parameter: any) => (
|
||||
<li className="mt-8 border-b pb-6">
|
||||
<div>
|
||||
<div className="flex gap-4 items-center">
|
||||
<span className="font-bold">{parameter.name}</span>
|
||||
<div className="font-mono text-xs break-all">
|
||||
{parameter.required && (
|
||||
<div className="text-[10px] border border-amber-700 bg-amber-300 text-amber-900 px-2 tracking-wide font-mono py-0.25 rounded-full">
|
||||
REQUIRED
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<p className="mt-4">{parameter.description}</p>
|
||||
</div>
|
||||
{parameter.example && (
|
||||
<div className="mt-4 flex gap-4 items-center">
|
||||
<span>Example:</span>
|
||||
<span className="font-mono text-xs break-all">
|
||||
{parameter.example}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Header Parameters */}
|
||||
{operation.parameters &&
|
||||
operation.parameters.filter((parameter) => parameter.in === 'header').length >
|
||||
0 && (
|
||||
<div className="mt-12">
|
||||
<h2 className="border-b pb-2 text-xl">Header parameters</h2>
|
||||
<ul className="mt-4">
|
||||
{operation.parameters &&
|
||||
operation.parameters
|
||||
.filter((parameter: any) => parameter.in === 'header')
|
||||
.map((parameter: any) => (
|
||||
<li className="mt-8 border-b pb-6">
|
||||
<div className="flex gap-4 items-center">
|
||||
<span className="font-bold">{parameter.name}</span>
|
||||
<span className="font-mono text-xs break-all">
|
||||
{parameter.required && 'required'}
|
||||
</span>
|
||||
</div>
|
||||
<div className="mt-4 flex gap-4 items-center">
|
||||
<span>Example:</span>
|
||||
<span className="font-mono text-xs break-all">
|
||||
{parameter.example}
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
</RefSubLayout.Details>
|
||||
<RefSubLayout.Examples>
|
||||
{operation.responseList.length > 0 && (
|
||||
<>
|
||||
<h2 className="text-xl">Responses</h2>
|
||||
<Tabs
|
||||
scrollable
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId={
|
||||
operation.responseList[0].responseCode ??
|
||||
operation.responseList[0].responseCode
|
||||
}
|
||||
queryGroup="response-status"
|
||||
>
|
||||
{operation.responseList.map((response: any) => (
|
||||
<Tabs.Panel id={response.responseCode} label={response.responseCode}>
|
||||
<p>{response.description}</p>
|
||||
{response?.content && response?.content['application/json'] && (
|
||||
<div className="mt-8">
|
||||
<CodeBlock language="bash" className="relative">
|
||||
{JSON.stringify(response.content['application/json'], null, 2)}
|
||||
</CodeBlock>
|
||||
</div>
|
||||
)}
|
||||
</Tabs.Panel>
|
||||
))}
|
||||
</Tabs>
|
||||
</>
|
||||
)}
|
||||
</RefSubLayout.Examples>
|
||||
</RefSubLayout.Section>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</RefSubLayout>
|
||||
)
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
import specFile from '~/spec/gotrue_v1_config.yaml' assert { type: 'yml' }
|
||||
import { Parameter } from '~/lib/refGenerator/refTypes'
|
||||
import ReactMarkdown from 'react-markdown'
|
||||
import Head from 'next/head'
|
||||
|
||||
// Parameters are grouped on the page by tag
|
||||
const TAGS = ['general']
|
||||
|
||||
export default function Config() {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Auth config</title>
|
||||
</Head>
|
||||
<div>
|
||||
<div className="flex my-16">
|
||||
<div className="w-full prose">
|
||||
<h1 className="text-4xl mb-16">{specFile.info.title} Configuration</h1>
|
||||
<ReactMarkdown>{specFile.info.description}</ReactMarkdown>
|
||||
<div>
|
||||
{TAGS.map((tag) =>
|
||||
specFile.parameters
|
||||
.filter((param: Parameter) => param.tags[0] === tag)
|
||||
.map((parameter: Parameter, index) => (
|
||||
<div>
|
||||
{index === 0 && <h2 className="text-xl capitalize">{tag}</h2>}
|
||||
<div className="mt-8">
|
||||
<div>
|
||||
<h2 className="text-xl font-medium text-foreground font-mono">
|
||||
<span className="mr-2">$</span>
|
||||
{parameter.title}
|
||||
</h2>
|
||||
<div className="grid" id={parameter.id}>
|
||||
<div className="border-b pb-8" key={parameter.id}>
|
||||
<div className=" mb-16">
|
||||
<p className="mb-4 scroll-mt-16 mt-0 text-foreground-light text-base">
|
||||
<ReactMarkdown>{parameter.description}</ReactMarkdown>
|
||||
</p>
|
||||
<div className="grid gap-2">
|
||||
<div className="flex gap-2">
|
||||
Required: <code>{parameter.required.toString()}</code>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
Default:
|
||||
<code>
|
||||
{parameter.default ? parameter.default.toString() : 'None'}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{parameter.links &&
|
||||
parameter.links.map((link) => (
|
||||
<div>
|
||||
<h3>See also:</h3>
|
||||
<li>
|
||||
<a href={link.link}>{link.name}</a>
|
||||
</li>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,17 +1,25 @@
|
||||
import spec from '~/spec/cli_v1_commands.yaml' assert { type: 'yml' }
|
||||
|
||||
import { flattenSections } from '~/lib/helpers'
|
||||
|
||||
import cliCommonSections from '~/spec/common-cli-sections.json' assert { type: 'json' }
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import RefSectionHandler from '~/components/reference/RefSectionHandler'
|
||||
import { flattenSections } from '~/lib/helpers'
|
||||
import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
|
||||
|
||||
import spec from '~/spec/cli_v1_commands.yaml' assert { type: 'yml' }
|
||||
import cliCommonSections from '~/spec/common-cli-sections.json' assert { type: 'json' }
|
||||
|
||||
const sections = flattenSections(cliCommonSections)
|
||||
const libraryPath = '/cli'
|
||||
|
||||
export default function CliRef(props) {
|
||||
return <RefSectionHandler sections={sections} spec={spec} pageProps={props} type="cli" />
|
||||
return (
|
||||
<RefSectionHandler
|
||||
menuId={MenuId.RefCli}
|
||||
sections={sections}
|
||||
spec={spec}
|
||||
pageProps={props}
|
||||
type="cli"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export async function getStaticProps() {
|
||||
|
||||
@@ -4,12 +4,21 @@ import RefSectionHandler from '~/components/reference/RefSectionHandler'
|
||||
import { flattenSections } from '~/lib/helpers'
|
||||
import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
|
||||
const sections = flattenSections(clientLibsCommonSections)
|
||||
const libraryPath = '/csharp'
|
||||
|
||||
export default function CSharpReference(props) {
|
||||
return <RefSectionHandler sections={sections} spec={spec} pageProps={props} type="client-lib" />
|
||||
return (
|
||||
<RefSectionHandler
|
||||
menuId={MenuId.RefCSharpV0}
|
||||
sections={sections}
|
||||
spec={spec}
|
||||
pageProps={props}
|
||||
type="client-lib"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export async function getStaticProps() {
|
||||
|
||||
@@ -7,6 +7,7 @@ import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
|
||||
import { useRouter } from 'next/router'
|
||||
import RefSEO from '~/components/reference/RefSEO'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
|
||||
const sections = flattenSections(clientLibsCommonSections)
|
||||
const libraryPath = '/csharp'
|
||||
@@ -25,6 +26,7 @@ export default function CSharpReference(props) {
|
||||
<RefSEO title={pageTitle} />
|
||||
|
||||
<RefSectionHandler
|
||||
menuId={MenuId.RefCSharpV0}
|
||||
sections={filteredSection}
|
||||
spec={spec}
|
||||
typeSpec={typeSpec}
|
||||
|
||||
@@ -4,12 +4,21 @@ import RefSectionHandler from '~/components/reference/RefSectionHandler'
|
||||
import { flattenSections } from '~/lib/helpers'
|
||||
import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
|
||||
const sections = flattenSections(clientLibsCommonSections)
|
||||
const libraryPath = '/csharp/v0'
|
||||
|
||||
export default function CSharpReference(props) {
|
||||
return <RefSectionHandler sections={sections} spec={spec} pageProps={props} type="client-lib" />
|
||||
return (
|
||||
<RefSectionHandler
|
||||
menuId={MenuId.RefCSharpV0}
|
||||
sections={sections}
|
||||
spec={spec}
|
||||
pageProps={props}
|
||||
type="client-lib"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export async function getStaticProps() {
|
||||
|
||||
@@ -7,6 +7,7 @@ import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
|
||||
import { useRouter } from 'next/router'
|
||||
import RefSEO from '~/components/reference/RefSEO'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
|
||||
const sections = flattenSections(clientLibsCommonSections)
|
||||
const libraryPath = '/csharp/v0'
|
||||
@@ -24,6 +25,7 @@ export default function JSReference(props) {
|
||||
<RefSEO title={pageTitle} />
|
||||
|
||||
<RefSectionHandler
|
||||
menuId={MenuId.RefCSharpV0}
|
||||
sections={filteredSection}
|
||||
spec={spec}
|
||||
typeSpec={typeSpec}
|
||||
|
||||
@@ -4,12 +4,21 @@ import RefSectionHandler from '~/components/reference/RefSectionHandler'
|
||||
import { flattenSections } from '~/lib/helpers'
|
||||
import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
|
||||
const sections = flattenSections(clientLibsCommonSections)
|
||||
const libraryPath = '/dart'
|
||||
|
||||
export default function DartReference(props) {
|
||||
return <RefSectionHandler sections={sections} spec={spec} pageProps={props} type="client-lib" />
|
||||
return (
|
||||
<RefSectionHandler
|
||||
menuId={MenuId.RefDartV2}
|
||||
sections={sections}
|
||||
spec={spec}
|
||||
pageProps={props}
|
||||
type="client-lib"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export async function getStaticProps() {
|
||||
|
||||
@@ -7,6 +7,7 @@ import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
|
||||
import { useRouter } from 'next/router'
|
||||
import RefSEO from '~/components/reference/RefSEO'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
|
||||
const sections = flattenSections(clientLibsCommonSections)
|
||||
const libraryPath = '/dart'
|
||||
@@ -25,6 +26,7 @@ export default function DartReference(props) {
|
||||
<RefSEO title={pageTitle} />
|
||||
|
||||
<RefSectionHandler
|
||||
menuId={MenuId.RefDartV2}
|
||||
sections={filteredSection}
|
||||
spec={spec}
|
||||
typeSpec={typeSpec}
|
||||
|
||||
@@ -4,6 +4,7 @@ import RefSectionHandler from '~/components/reference/RefSectionHandler'
|
||||
import { flattenSections } from '~/lib/helpers'
|
||||
import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
|
||||
const sections = flattenSections(clientLibsCommonSections)
|
||||
const libraryPath = '/dart/v0'
|
||||
@@ -11,6 +12,7 @@ const libraryPath = '/dart/v0'
|
||||
export default function JSReference(props) {
|
||||
return (
|
||||
<RefSectionHandler
|
||||
menuId={MenuId.RefDartV1}
|
||||
sections={sections}
|
||||
spec={spec}
|
||||
pageProps={props}
|
||||
|
||||
@@ -7,6 +7,7 @@ import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
|
||||
import { useRouter } from 'next/router'
|
||||
import RefSEO from '~/components/reference/RefSEO'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
|
||||
const sections = flattenSections(clientLibsCommonSections)
|
||||
const libraryPath = '/dart/v0'
|
||||
@@ -24,6 +25,7 @@ export default function DartReference(props) {
|
||||
<RefSEO title={pageTitle} />
|
||||
|
||||
<RefSectionHandler
|
||||
menuId={MenuId.RefDartV1}
|
||||
sections={filteredSection}
|
||||
spec={spec}
|
||||
typeSpec={typeSpec}
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
import clientLibsCommonSections from '~/spec/common-client-libs-sections.json'
|
||||
import typeSpec from '~/spec/enrichments/tsdoc_v2/combined.json'
|
||||
import spec from '~/spec/supabase_js_v2.yml' assert { type: 'yml' }
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import RefSectionHandler from '~/components/reference/RefSectionHandler'
|
||||
import { flattenSections } from '~/lib/helpers'
|
||||
import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
|
||||
|
||||
import clientLibsCommonSections from '~/spec/common-client-libs-sections.json' assert { type: 'json' }
|
||||
import typeSpec from '~/spec/enrichments/tsdoc_v2/combined.json' assert { type: 'json' }
|
||||
import spec from '~/spec/supabase_js_v2.yml' assert { type: 'yml' }
|
||||
|
||||
const sections = flattenSections(clientLibsCommonSections)
|
||||
const libraryPath = '/javascript'
|
||||
|
||||
export default function JSReference(props) {
|
||||
return (
|
||||
<RefSectionHandler
|
||||
menuId={MenuId.RefJavaScriptV2}
|
||||
sections={sections}
|
||||
spec={spec}
|
||||
typeSpec={typeSpec}
|
||||
|
||||
@@ -7,6 +7,7 @@ import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
|
||||
import { useRouter } from 'next/router'
|
||||
import RefSEO from '~/components/reference/RefSEO'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
|
||||
const sections = flattenSections(clientLibsCommonSections)
|
||||
const libraryPath = '/javascript'
|
||||
@@ -25,6 +26,7 @@ export default function JSReference(props) {
|
||||
<RefSEO title={pageTitle} />
|
||||
|
||||
<RefSectionHandler
|
||||
menuId={MenuId.RefJavaScriptV2}
|
||||
sections={filteredSection}
|
||||
spec={spec}
|
||||
typeSpec={typeSpec}
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
import clientLibsCommonSections from '~/spec/common-client-libs-sections.json'
|
||||
import typeSpec from '~/spec/enrichments/tsdoc_v1/combined.json'
|
||||
import spec from '~/spec/supabase_js_v1.yml' assert { type: 'yml' }
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import RefSectionHandler from '~/components/reference/RefSectionHandler'
|
||||
import { flattenSections } from '~/lib/helpers'
|
||||
import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
|
||||
|
||||
import clientLibsCommonSections from '~/spec/common-client-libs-sections.json' assert { type: 'json' }
|
||||
import typeSpec from '~/spec/enrichments/tsdoc_v1/combined.json' assert { type: 'json' }
|
||||
import spec from '~/spec/supabase_js_v1.yml' assert { type: 'yml' }
|
||||
|
||||
const sections = flattenSections(clientLibsCommonSections)
|
||||
const libraryPath = '/javascript/v1'
|
||||
|
||||
export default function JSReference(props) {
|
||||
return (
|
||||
<RefSectionHandler
|
||||
menuId={MenuId.RefJavaScriptV1}
|
||||
sections={sections}
|
||||
spec={spec}
|
||||
typeSpec={typeSpec}
|
||||
|
||||
@@ -7,6 +7,7 @@ import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
|
||||
import { useRouter } from 'next/router'
|
||||
import RefSEO from '~/components/reference/RefSEO'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
|
||||
const sections = flattenSections(clientLibsCommonSections)
|
||||
const libraryPath = '/javascript/v1'
|
||||
@@ -25,6 +26,7 @@ export default function JSReference(props) {
|
||||
<RefSEO title={pageTitle} />
|
||||
|
||||
<RefSectionHandler
|
||||
menuId={MenuId.RefJavaScriptV1}
|
||||
sections={filteredSection}
|
||||
spec={spec}
|
||||
typeSpec={typeSpec}
|
||||
|
||||
@@ -4,12 +4,21 @@ import RefSectionHandler from '~/components/reference/RefSectionHandler'
|
||||
import { flattenSections } from '~/lib/helpers'
|
||||
import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
|
||||
const sections = flattenSections(clientLibsCommonSections)
|
||||
const libraryPath = '/kotlin'
|
||||
|
||||
export default function KotlinReference(props) {
|
||||
return <RefSectionHandler sections={sections} spec={spec} pageProps={props} type="client-lib" />
|
||||
return (
|
||||
<RefSectionHandler
|
||||
menuId={MenuId.RefKotlinV2}
|
||||
sections={sections}
|
||||
spec={spec}
|
||||
pageProps={props}
|
||||
type="client-lib"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export async function getStaticProps() {
|
||||
|
||||
@@ -7,6 +7,7 @@ import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
|
||||
import { useRouter } from 'next/router'
|
||||
import RefSEO from '~/components/reference/RefSEO'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
|
||||
const sections = flattenSections(clientLibsCommonSections)
|
||||
const libraryPath = '/kotlin'
|
||||
@@ -25,6 +26,7 @@ export default function KotlinReference(props) {
|
||||
<RefSEO title={pageTitle} />
|
||||
|
||||
<RefSectionHandler
|
||||
menuId={MenuId.RefKotlinV2}
|
||||
sections={filteredSection}
|
||||
spec={spec}
|
||||
typeSpec={typeSpec}
|
||||
|
||||
@@ -4,6 +4,7 @@ import RefSectionHandler from '~/components/reference/RefSectionHandler'
|
||||
import { flattenSections } from '~/lib/helpers'
|
||||
import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
|
||||
const sections = flattenSections(clientLibsCommonSections)
|
||||
const libraryPath = '/kotlin/v1'
|
||||
@@ -11,6 +12,7 @@ const libraryPath = '/kotlin/v1'
|
||||
export default function KotlinReference(props) {
|
||||
return (
|
||||
<RefSectionHandler
|
||||
menuId={MenuId.RefKotlinV1}
|
||||
sections={sections}
|
||||
spec={spec}
|
||||
pageProps={props}
|
||||
|
||||
@@ -7,6 +7,7 @@ import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
|
||||
import { useRouter } from 'next/router'
|
||||
import RefSEO from '~/components/reference/RefSEO'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
|
||||
const sections = flattenSections(clientLibsCommonSections)
|
||||
const libraryPath = '/kotlin/v1'
|
||||
@@ -24,6 +25,7 @@ export default function KotlinReference(props) {
|
||||
<RefSEO title={pageTitle} />
|
||||
|
||||
<RefSectionHandler
|
||||
menuId={MenuId.RefKotlinV1}
|
||||
sections={filteredSection}
|
||||
spec={spec}
|
||||
typeSpec={typeSpec}
|
||||
|
||||
@@ -5,6 +5,7 @@ import RefSectionHandler from '~/components/reference/RefSectionHandler'
|
||||
import { flattenSections } from '~/lib/helpers'
|
||||
import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
|
||||
const sections = flattenSections(clientLibsCommonSections)
|
||||
const libraryPath = '/python'
|
||||
@@ -12,6 +13,7 @@ const libraryPath = '/python'
|
||||
export default function PyReference(props) {
|
||||
return (
|
||||
<RefSectionHandler
|
||||
menuId={MenuId.RefPythonV2}
|
||||
sections={sections}
|
||||
spec={spec}
|
||||
typeSpec={typeSpec}
|
||||
|
||||
@@ -7,6 +7,7 @@ import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
|
||||
import { useRouter } from 'next/router'
|
||||
import RefSEO from '~/components/reference/RefSEO'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
|
||||
const sections = flattenSections(clientLibsCommonSections)
|
||||
const libraryPath = '/python'
|
||||
@@ -25,6 +26,7 @@ export default function PyReference(props) {
|
||||
<RefSEO title={pageTitle} />
|
||||
|
||||
<RefSectionHandler
|
||||
menuId={MenuId.RefPythonV2}
|
||||
sections={filteredSection}
|
||||
spec={spec}
|
||||
typeSpec={typeSpec}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import analyticsSpec from '~/spec/transforms/analytics_v0_openapi_deparsed.json' assert { type: 'json' }
|
||||
import selfHostingAnalyticsCommonSections from '~/spec/common-self-hosting-analytics-sections.json'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import RefSectionHandler from '~/components/reference/RefSectionHandler'
|
||||
import { flattenSections } from '~/lib/helpers'
|
||||
import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
|
||||
import { gen_v3 } from '~/lib/refGenerator/helpers'
|
||||
|
||||
import selfHostingAnalyticsCommonSections from '~/spec/common-self-hosting-analytics-sections.json' assert { type: 'json' }
|
||||
import analyticsSpec from '~/spec/transforms/analytics_v0_openapi_deparsed.json' assert { type: 'json' }
|
||||
|
||||
const sections = flattenSections(selfHostingAnalyticsCommonSections)
|
||||
const libraryPath = '/self-hosting-analytics'
|
||||
|
||||
@@ -13,7 +15,15 @@ const libraryPath = '/self-hosting-analytics'
|
||||
const spec = gen_v3(analyticsSpec, 'wat', { apiUrl: 'apiv0' })
|
||||
|
||||
export default function SelfHostAnalyticsReference(props) {
|
||||
return <RefSectionHandler sections={sections} spec={spec} pageProps={props} type="api" />
|
||||
return (
|
||||
<RefSectionHandler
|
||||
menuId={MenuId.SelfHostingAnalytics}
|
||||
sections={sections}
|
||||
spec={spec}
|
||||
pageProps={props}
|
||||
type="api"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export async function getStaticProps() {
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import authSpec from '~/spec/auth_v1_openapi.json' assert { type: 'json' }
|
||||
import selfHostingAuthCommonSections from '~/spec/common-self-hosting-auth-sections.json'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import RefSectionHandler from '~/components/reference/RefSectionHandler'
|
||||
import { flattenSections } from '~/lib/helpers'
|
||||
import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
|
||||
import { gen_v3 } from '~/lib/refGenerator/helpers'
|
||||
|
||||
import authSpec from '~/spec/auth_v1_openapi.json' assert { type: 'json' }
|
||||
import selfHostingAuthCommonSections from '~/spec/common-self-hosting-auth-sections.json'
|
||||
|
||||
const sections = flattenSections(selfHostingAuthCommonSections)
|
||||
const libraryPath = '/self-hosting-auth'
|
||||
|
||||
@@ -13,7 +15,15 @@ const libraryPath = '/self-hosting-auth'
|
||||
const spec = gen_v3(authSpec, 'wat', { apiUrl: 'apiv0' })
|
||||
|
||||
export default function SelfHostAuthReference(props) {
|
||||
return <RefSectionHandler sections={sections} spec={spec} pageProps={props} type="api" />
|
||||
return (
|
||||
<RefSectionHandler
|
||||
menuId={MenuId.SelfHostingAuth}
|
||||
sections={sections}
|
||||
spec={spec}
|
||||
pageProps={props}
|
||||
type="api"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export async function getStaticProps() {
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
import selfHostingFunctionsCommonSections from '~/spec/common-self-hosting-functions-sections.json'
|
||||
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import RefSectionHandler from '~/components/reference/RefSectionHandler'
|
||||
import { flattenSections } from '~/lib/helpers'
|
||||
import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
|
||||
import { gen_v3 } from '~/lib/refGenerator/helpers'
|
||||
|
||||
import selfHostingFunctionsCommonSections from '~/spec/common-self-hosting-functions-sections.json' assert { type: 'json' }
|
||||
|
||||
const sections = flattenSections(selfHostingFunctionsCommonSections)
|
||||
const libraryPath = '/self-hosting-functions'
|
||||
|
||||
export default function SelfHostFunctionsReference(props) {
|
||||
return <RefSectionHandler sections={sections} pageProps={props} type="api" />
|
||||
return (
|
||||
<RefSectionHandler
|
||||
menuId={MenuId.SelfHostingFunctions}
|
||||
sections={sections}
|
||||
pageProps={props}
|
||||
type="api"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export async function getStaticProps() {
|
||||
|
||||
@@ -1,15 +1,23 @@
|
||||
import selfHostingRealtimeCommonSections from '~/spec/common-self-hosting-realtime-sections.json'
|
||||
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import RefSectionHandler from '~/components/reference/RefSectionHandler'
|
||||
import { flattenSections } from '~/lib/helpers'
|
||||
import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
|
||||
|
||||
import selfHostingRealtimeCommonSections from '~/spec/common-self-hosting-realtime-sections.json' assert { type: 'json' }
|
||||
|
||||
const sections = flattenSections(selfHostingRealtimeCommonSections)
|
||||
const libraryPath = '/self-hosting-realtime'
|
||||
|
||||
export default function SelfHostRealtimeReference(props) {
|
||||
return <RefSectionHandler sections={sections} pageProps={props} type="api" />
|
||||
return (
|
||||
<RefSectionHandler
|
||||
menuId={MenuId.SelfHostingRealtime}
|
||||
sections={sections}
|
||||
pageProps={props}
|
||||
type="api"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export async function getStaticProps() {
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import storageSpec from '~/spec/storage_v0_openapi.json' assert { type: 'json' }
|
||||
import selfHostingStorageCommonSections from '~/spec/common-self-hosting-storage-sections.json'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import RefSectionHandler from '~/components/reference/RefSectionHandler'
|
||||
import { flattenSections } from '~/lib/helpers'
|
||||
import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
|
||||
import { gen_v3 } from '~/lib/refGenerator/helpers'
|
||||
|
||||
import storageSpec from '~/spec/storage_v0_openapi.json' assert { type: 'json' }
|
||||
import selfHostingStorageCommonSections from '~/spec/common-self-hosting-storage-sections.json' assert { type: 'json' }
|
||||
|
||||
const sections = flattenSections(selfHostingStorageCommonSections)
|
||||
const libraryPath = '/self-hosting-storage'
|
||||
|
||||
@@ -13,7 +15,15 @@ const libraryPath = '/self-hosting-storage'
|
||||
const spec = gen_v3(storageSpec, 'wat', { apiUrl: 'apiv0' })
|
||||
|
||||
export default function SelfHostStorageReference(props) {
|
||||
return <RefSectionHandler sections={sections} spec={spec} pageProps={props} type="api" />
|
||||
return (
|
||||
<RefSectionHandler
|
||||
menuId={MenuId.SelfHostingStorage}
|
||||
sections={sections}
|
||||
spec={spec}
|
||||
pageProps={props}
|
||||
type="api"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export async function getStaticProps() {
|
||||
|
||||
@@ -4,12 +4,21 @@ import RefSectionHandler from '~/components/reference/RefSectionHandler'
|
||||
import { flattenSections } from '~/lib/helpers'
|
||||
import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
|
||||
const sections = flattenSections(clientLibsCommonSections)
|
||||
const libraryPath = '/swift'
|
||||
|
||||
export default function SwiftReference(props) {
|
||||
return <RefSectionHandler sections={sections} spec={spec} pageProps={props} type="client-lib" />
|
||||
return (
|
||||
<RefSectionHandler
|
||||
menuId={MenuId.RefSwiftV2}
|
||||
sections={sections}
|
||||
spec={spec}
|
||||
pageProps={props}
|
||||
type="client-lib"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export async function getStaticProps() {
|
||||
|
||||
@@ -7,6 +7,7 @@ import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
|
||||
import { useRouter } from 'next/router'
|
||||
import RefSEO from '~/components/reference/RefSEO'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
|
||||
const sections = flattenSections(clientLibsCommonSections)
|
||||
const libraryPath = '/swift'
|
||||
@@ -25,6 +26,7 @@ export default function SwiftReference(props) {
|
||||
<RefSEO title={pageTitle} />
|
||||
|
||||
<RefSectionHandler
|
||||
menuId={MenuId.RefSwiftV2}
|
||||
sections={filteredSection}
|
||||
spec={spec}
|
||||
typeSpec={typeSpec}
|
||||
|
||||
+10
-1
@@ -4,12 +4,21 @@ import RefSectionHandler from '~/components/reference/RefSectionHandler'
|
||||
import { flattenSections } from '~/lib/helpers'
|
||||
import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
|
||||
const sections = flattenSections(clientLibsCommonSections)
|
||||
const libraryPath = '/swift/v2'
|
||||
|
||||
export default function SwiftReference(props) {
|
||||
return <RefSectionHandler sections={sections} spec={spec} pageProps={props} type="client-lib" />
|
||||
return (
|
||||
<RefSectionHandler
|
||||
menuId={MenuId.RefSwiftV1}
|
||||
sections={sections}
|
||||
spec={spec}
|
||||
pageProps={props}
|
||||
type="client-lib"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export async function getStaticProps() {
|
||||
+2
@@ -7,6 +7,7 @@ import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
|
||||
import { useRouter } from 'next/router'
|
||||
import RefSEO from '~/components/reference/RefSEO'
|
||||
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
|
||||
const sections = flattenSections(clientLibsCommonSections)
|
||||
const libraryPath = '/swift/v2'
|
||||
@@ -24,6 +25,7 @@ export default function SwiftReference(props) {
|
||||
<RefSEO title={pageTitle} />
|
||||
|
||||
<RefSectionHandler
|
||||
menuId={MenuId.RefSwiftV1}
|
||||
sections={filteredSection}
|
||||
spec={spec}
|
||||
typeSpec={typeSpec}
|
||||
@@ -35,6 +35,7 @@ Jordi Enric
|
||||
Joshen Lim
|
||||
Kamil Ogórek
|
||||
Kang Ming Tay
|
||||
Karan S
|
||||
Karlo Ison
|
||||
Kevin Brolly
|
||||
Kevin Grüneberg
|
||||
@@ -55,6 +56,7 @@ Qiao Han
|
||||
Raminder Singh
|
||||
Rodrigo Mansueli
|
||||
Rory Wilding
|
||||
Sam Rose
|
||||
Sreyas Udayavarman
|
||||
Stanislav M
|
||||
Steve Chavez
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 119 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 126 KiB |
+10
-11
@@ -11,10 +11,15 @@
|
||||
FROM node:18-slim as base
|
||||
|
||||
# Fixes issues with Sentry CLI and SSL certificates during build
|
||||
# TODO: Git is added because it's needed to build libpg, remove it once they publish a binary on the S3 bucket
|
||||
RUN apt-get update -qq && \
|
||||
apt-get install -y ca-certificates && \
|
||||
rm -rf /var/lib/apt/lists/* && \
|
||||
update-ca-certificates
|
||||
apt-get install -y --no-install-recommends \
|
||||
git \
|
||||
python3 \
|
||||
ca-certificates \
|
||||
build-essential && \
|
||||
rm -rf /var/lib/apt/lists/* && \
|
||||
update-ca-certificates
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
@@ -22,19 +27,13 @@ WORKDIR /app
|
||||
FROM base as turbo
|
||||
COPY . .
|
||||
|
||||
RUN npx turbo@1.10.3 prune --scope=studio --docker
|
||||
RUN npx turbo@1.12.3 prune --scope=studio --docker
|
||||
|
||||
# Install dev dependencies (only if needed)
|
||||
FROM base as deps
|
||||
COPY --from=turbo /app/out/json ./
|
||||
COPY --from=turbo /app/out/package-lock.json ./
|
||||
# Install additional dependencies for arm64 build (required by bufferutil)
|
||||
ARG TARGETARCH
|
||||
RUN if [ "$TARGETARCH" = "arm64" ]; then \
|
||||
apt-get update && apt-get install -y --no-install-recommends \
|
||||
python3 \
|
||||
build-essential \
|
||||
&& rm -rf /var/lib/apt/lists/*; fi
|
||||
|
||||
# No need to clean cache because production uses standalone build
|
||||
RUN npm clean-install
|
||||
|
||||
|
||||
@@ -130,9 +130,6 @@ export const AIPolicyEditorPanel = memo(function ({
|
||||
|
||||
const { mutateAsync: debugSql, isLoading: isDebugSqlLoading } = useSqlDebugMutation()
|
||||
|
||||
const errorLines =
|
||||
error?.formattedError.split('\n').filter((x: string) => x.length > 0).length ?? 0
|
||||
|
||||
const onExecuteSQL = useCallback(() => {
|
||||
// clean up the sql before sending
|
||||
const policy = editorRef.current?.getValue().replaceAll(' ', ' ')
|
||||
|
||||
@@ -15,8 +15,8 @@ import {
|
||||
|
||||
import { useCheckPermissions } from 'hooks'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
import CreateUserModal from './CreateUserModal'
|
||||
import InviteUserModal from './InviteUserModal'
|
||||
import CreateUserModal from './CreateUserModal'
|
||||
|
||||
export type AddUserDropdownProps = {
|
||||
projectKpsVersion?: string
|
||||
|
||||
@@ -61,6 +61,7 @@ const PITRStatus = ({
|
||||
</div>
|
||||
<Tooltip.Root delayDuration={0}>
|
||||
<Tooltip.Trigger asChild>
|
||||
{/* [Joshen TODO] Double check if this is intentional */}
|
||||
<Button
|
||||
disabled={hasReadReplicas || !canTriggerPhysicalBackup}
|
||||
onClick={() => onSetConfiguration()}
|
||||
@@ -68,23 +69,28 @@ const PITRStatus = ({
|
||||
Start a restore
|
||||
</Button>
|
||||
</Tooltip.Trigger>
|
||||
{!canTriggerPhysicalBackup && (
|
||||
<Tooltip.Portal>
|
||||
<Tooltip.Content side="left">
|
||||
<Tooltip.Arrow className="radix-tooltip-arrow" />
|
||||
<div
|
||||
className={[
|
||||
'rounded bg-alternative py-1 px-2 leading-none shadow',
|
||||
'border border-background',
|
||||
].join(' ')}
|
||||
>
|
||||
<span className="text-xs text-foreground">
|
||||
You need additional permissions to trigger a PITR recovery
|
||||
</span>
|
||||
</div>
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Portal>
|
||||
)}
|
||||
{hasReadReplicas ||
|
||||
(!canTriggerPhysicalBackup && (
|
||||
<Tooltip.Portal>
|
||||
<Tooltip.Content side="left">
|
||||
<Tooltip.Arrow className="radix-tooltip-arrow" />
|
||||
<div
|
||||
className={[
|
||||
'rounded bg-alternative py-1 px-2 leading-none shadow',
|
||||
'border border-background',
|
||||
].join(' ')}
|
||||
>
|
||||
<span className="text-xs text-foreground">
|
||||
{hasReadReplicas
|
||||
? 'You will need to remove all read replicas first to trigger a PITR recovery'
|
||||
: !canTriggerPhysicalBackup
|
||||
? 'You need additional permissions to trigger a PITR recovery'
|
||||
: null}
|
||||
</span>
|
||||
</div>
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Portal>
|
||||
))}
|
||||
</Tooltip.Root>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import { useTheme } from 'next-themes'
|
||||
import 'reactflow/dist/style.css'
|
||||
import { IconLoader } from 'ui'
|
||||
import { TABLE_NODE_ROW_HEIGHT, TABLE_NODE_WIDTH, TableNode } from 'ui-patterns/SchemaTableNode'
|
||||
import SchemaGraphLegend from './SchemaGraphLegend'
|
||||
|
||||
type TableNodeData = {
|
||||
name: string
|
||||
@@ -259,6 +260,7 @@ const TablesGraph = ({ tables }: { tables: PostgresTable[] }) => {
|
||||
maskColor={miniMapMaskColor}
|
||||
className="border rounded-md shadow-sm"
|
||||
/>
|
||||
<SchemaGraphLegend />
|
||||
</ReactFlow>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { DiamondIcon, Fingerprint, Hash, Key } from 'lucide-react'
|
||||
|
||||
const SchemaGraphLegend = () => {
|
||||
return (
|
||||
<div className="absolute bottom-0 left-0 border-t flex justify-center px-1 py-2 shadow-md bg-surface-100 w-full z-10">
|
||||
{/* <h3 className="text-xs font-bold">Legend</h3> */}
|
||||
<ul className="flex flex-wrap items-center justify-center gap-4">
|
||||
<li className="flex items-center text-xs font-mono gap-1">
|
||||
<Key size={15} strokeWidth={1.5} className="flex-shrink-0 text-light" />
|
||||
Primary key
|
||||
</li>
|
||||
<li className="flex items-center text-xs font-mono gap-1">
|
||||
<Hash size={15} strokeWidth={1.5} className="flex-shrink-0 text-light" />
|
||||
Identity
|
||||
</li>
|
||||
<li className="flex items-center text-xs font-mono gap-1">
|
||||
<Fingerprint size={15} strokeWidth={1.5} className="flex-shrink-0 text-light" />
|
||||
Unique
|
||||
</li>
|
||||
<li className="flex items-center text-xs font-mono gap-1">
|
||||
<DiamondIcon size={15} strokeWidth={1.5} className="flex-shrink-0 text-light" />
|
||||
Nullable
|
||||
</li>
|
||||
<li className="flex items-center text-xs font-mono gap-1">
|
||||
<DiamondIcon
|
||||
size={15}
|
||||
strokeWidth={1.5}
|
||||
fill="currentColor"
|
||||
className="flex-shrink-0 text-light"
|
||||
/>
|
||||
Non-Nullable
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default SchemaGraphLegend
|
||||
@@ -155,6 +155,20 @@ export const FRAMEWORKS: ConnectionType[] = [
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'exporeactnative',
|
||||
label: 'Expo React Native',
|
||||
icon: 'expo',
|
||||
guideLink: 'https://supabase.com/docs/guides/getting-started/tutorials/with-expo-react-native',
|
||||
children: [
|
||||
{
|
||||
key: 'supabasejs',
|
||||
label: 'Supabase-js',
|
||||
children: [],
|
||||
icon: 'supabase',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
export const ORMS: ConnectionType[] = [
|
||||
|
||||
@@ -13,7 +13,7 @@ const ConnectionIcon = ({ connection }: ConnectionIconProps) => {
|
||||
<Image
|
||||
className="transition-all group-hover:scale-110"
|
||||
src={`${BASE_PATH}/img/libraries/${connection.toLowerCase()}${
|
||||
['expo', 'nextjs', 'prisma', 'drizzle', 'astro'].includes(connection.toLowerCase())
|
||||
['expo', 'nextjs', 'prisma', 'drizzle', 'astro', 'remix'].includes(connection.toLowerCase())
|
||||
? resolvedTheme?.includes('dark')
|
||||
? '-dark'
|
||||
: ''
|
||||
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
import { ContentFileProps } from 'components/interfaces/Home/Connect/Connect.types'
|
||||
|
||||
import {
|
||||
ConnectTabs,
|
||||
ConnectTabTrigger,
|
||||
ConnectTabTriggers,
|
||||
ConnectTabContent,
|
||||
} from 'components/interfaces/Home/Connect/ConnectTabs'
|
||||
import SimpleCodeBlock from 'components/to-be-cleaned/SimpleCodeBlock'
|
||||
|
||||
const ContentFile = ({ projectKeys }: ContentFileProps) => {
|
||||
return (
|
||||
<ConnectTabs>
|
||||
<ConnectTabTriggers>
|
||||
<ConnectTabTrigger value=".env.local" />
|
||||
<ConnectTabTrigger value="utils/supabase.ts" />
|
||||
<ConnectTabTrigger value="App.tsx" />
|
||||
</ConnectTabTriggers>
|
||||
|
||||
<ConnectTabContent value=".env.local">
|
||||
<SimpleCodeBlock className="bash" parentClassName="min-h-72">
|
||||
{`
|
||||
SUPABASE_URL=${projectKeys.apiUrl ?? 'your-project-url'}
|
||||
SUPABASE_ANON_KEY=${projectKeys.anonKey ?? 'your-anon-key'}
|
||||
`}
|
||||
</SimpleCodeBlock>
|
||||
</ConnectTabContent>
|
||||
|
||||
<ConnectTabContent value="utils/supabase.ts">
|
||||
<SimpleCodeBlock className="ts" parentClassName="min-h-72">
|
||||
{`
|
||||
import 'react-native-url-polyfill/auto'
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage'
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import { SUPABASE_URL, SUPABASE_ANON_KEY } from "@env";
|
||||
|
||||
export const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, {
|
||||
auth: {
|
||||
storage: AsyncStorage,
|
||||
autoRefreshToken: true,
|
||||
persistSession: true,
|
||||
detectSessionInUrl: false,
|
||||
},
|
||||
})
|
||||
`}
|
||||
</SimpleCodeBlock>
|
||||
</ConnectTabContent>
|
||||
|
||||
<ConnectTabContent value="App.tsx">
|
||||
<SimpleCodeBlock className="tsx" parentClassName="min-h-72">
|
||||
{`
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { View, Text, FlatList } from 'react-native';
|
||||
import { supabase } from '../utils/supabase';
|
||||
|
||||
export default function App() {
|
||||
const [todos, setTodos] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
const getTodos = async () => {
|
||||
try {
|
||||
const { data: todos, error } = await supabase.from('todos').select();
|
||||
|
||||
if (error) {
|
||||
console.error('Error fetching todos:', error.message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (todos && todos.length > 0) {
|
||||
setTodos(todos);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching todos:', error.message);
|
||||
}
|
||||
};
|
||||
|
||||
getTodos();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
|
||||
<Text>Todo List</Text>
|
||||
<FlatList
|
||||
data={todos}
|
||||
keyExtractor={(item) => item.id.toString()}
|
||||
renderItem={({ item }) => <Text key={item.id}>{item.title}</Text>}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
`}
|
||||
</SimpleCodeBlock>
|
||||
</ConnectTabContent>
|
||||
</ConnectTabs>
|
||||
)
|
||||
}
|
||||
|
||||
export default ContentFile
|
||||
@@ -43,6 +43,7 @@ const ProjectList = ({ search, rewriteHref }: ProjectListProps) => {
|
||||
const projectsByOrg = groupBy(allProjects, 'organization_id')
|
||||
const isLoadingPermissions = IS_PLATFORM ? _isLoadingPermissions : false
|
||||
const noResults =
|
||||
search.length > 0 &&
|
||||
allProjects !== undefined &&
|
||||
allProjects.filter((project) => {
|
||||
return (
|
||||
|
||||
@@ -54,7 +54,7 @@ const HomePageActions = ({
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
{IS_PLATFORM && organizationCreationEnabled && orgsLoaded && organizations.length !== 0 && (
|
||||
{IS_PLATFORM && organizationCreationEnabled && orgsLoaded && (
|
||||
<Button type="default" asChild>
|
||||
<Link href="/new" className="flex items-center gap-2">
|
||||
New organization
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { useTelemetryProps } from 'common'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import { Dispatch, SetStateAction, useState } from 'react'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import {
|
||||
@@ -16,6 +18,7 @@ import {
|
||||
} from 'ui'
|
||||
import * as z from 'zod'
|
||||
|
||||
import Telemetry from 'lib/telemetry'
|
||||
import { RealtimeConfig } from '../useRealtimeMessages'
|
||||
|
||||
interface ChooseChannelPopoverProps {
|
||||
@@ -25,6 +28,8 @@ interface ChooseChannelPopoverProps {
|
||||
|
||||
export const ChooseChannelPopover = ({ config, onChangeConfig }: ChooseChannelPopoverProps) => {
|
||||
const [open, setOpen] = useState(false)
|
||||
const telemetryProps = useTelemetryProps()
|
||||
const router = useRouter()
|
||||
|
||||
const FormSchema = z.object({ channel: z.string() })
|
||||
const form = useForm<z.infer<typeof FormSchema>>({
|
||||
@@ -44,6 +49,15 @@ export const ChooseChannelPopover = ({ config, onChangeConfig }: ChooseChannelPo
|
||||
|
||||
const onSubmit = () => {
|
||||
setOpen(false)
|
||||
Telemetry.sendEvent(
|
||||
{
|
||||
category: 'realtime_inspector',
|
||||
action: 'started_listening_to_channel_in_input_channel_popover',
|
||||
label: 'realtime_inspector_config',
|
||||
},
|
||||
telemetryProps,
|
||||
router
|
||||
)
|
||||
onChangeConfig({ ...config, channelName: form.getValues('channel'), enabled: true })
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,9 @@ import { PlayCircle, StopCircle } from 'lucide-react'
|
||||
import { Dispatch, SetStateAction } from 'react'
|
||||
import { Button } from 'ui'
|
||||
|
||||
import { useTelemetryProps } from 'common'
|
||||
import Telemetry from 'lib/telemetry'
|
||||
import { useRouter } from 'next/router'
|
||||
import { ChooseChannelPopover } from './ChooseChannelPopover'
|
||||
import { RealtimeFilterPopover } from './RealtimeFilterPopover'
|
||||
import { RealtimeTokensPopover } from './RealtimeTokensPopover'
|
||||
@@ -14,6 +17,9 @@ interface HeaderProps {
|
||||
}
|
||||
|
||||
export const Header = ({ config, onChangeConfig }: HeaderProps) => {
|
||||
const telemetryProps = useTelemetryProps()
|
||||
const router = useRouter()
|
||||
|
||||
return (
|
||||
<div className="flex flex-row h-14 gap-2.5 items-center px-4">
|
||||
<div className="flex flex-row">
|
||||
@@ -27,7 +33,21 @@ export const Header = ({ config, onChangeConfig }: HeaderProps) => {
|
||||
className="rounded-l-none border-l-0"
|
||||
disabled={config.channelName.length === 0}
|
||||
icon={config.enabled ? <StopCircle size="16" /> : <PlayCircle size="16" />}
|
||||
onClick={() => onChangeConfig({ ...config, enabled: !config.enabled })}
|
||||
onClick={() => {
|
||||
onChangeConfig({ ...config, enabled: !config.enabled })
|
||||
if (!config.enabled) {
|
||||
// the user has clicked to start listening
|
||||
Telemetry.sendEvent(
|
||||
{
|
||||
category: 'realtime_inspector',
|
||||
action: 'started_listening',
|
||||
label: 'realtime_inspector_config',
|
||||
},
|
||||
telemetryProps,
|
||||
router
|
||||
)
|
||||
}
|
||||
}}
|
||||
>
|
||||
{config.enabled ? `Stop listening` : `Start listening`}
|
||||
</Button>
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { useTelemetryProps } from 'common'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useMemo } from 'react'
|
||||
import { Button, IconX, cn } from 'ui'
|
||||
|
||||
import CopyButton from 'components/ui/CopyButton'
|
||||
import Telemetry from 'lib/telemetry'
|
||||
import { LogData } from './Messages.types'
|
||||
import { SelectedRealtimeMessagePanel } from './SelectedRealtimeMessagePanel'
|
||||
|
||||
@@ -11,6 +14,9 @@ export interface MessageSelectionProps {
|
||||
}
|
||||
|
||||
const MessageSelection = ({ log, onClose }: MessageSelectionProps) => {
|
||||
const telemetryProps = useTelemetryProps()
|
||||
const router = useRouter()
|
||||
|
||||
const selectionText = useMemo(() => {
|
||||
return JSON.stringify(log, null, 2)
|
||||
}, [log])
|
||||
@@ -64,7 +70,22 @@ const MessageSelection = ({ log, onClose }: MessageSelectionProps) => {
|
||||
<div className="pt-4 flex flex-col gap-4">
|
||||
<div className="px-4 flex flex-row justify-between items-center">
|
||||
<div className="transition">
|
||||
<CopyButton text={selectionText} type="default" title="Copy log to clipboard" />
|
||||
<CopyButton
|
||||
text={selectionText}
|
||||
type="default"
|
||||
title="Copy log to clipboard"
|
||||
onClick={() => {
|
||||
Telemetry.sendEvent(
|
||||
{
|
||||
category: 'realtime_inspector',
|
||||
action: 'copied_message',
|
||||
label: 'realtime_inspector_results',
|
||||
},
|
||||
telemetryProps,
|
||||
router
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
type="text"
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { useParams, useTelemetryProps } from 'common'
|
||||
import { isEqual } from 'lodash'
|
||||
import { Loader2, MegaphoneIcon } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { Key, useEffect, useState } from 'react'
|
||||
import DataGrid, { RenderRowProps, Row } from 'react-data-grid'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import ShimmerLine from 'components/ui/ShimmerLine'
|
||||
import { Button, IconBroadcast, IconDatabaseChanges, IconExternalLink, IconPresence, cn } from 'ui'
|
||||
|
||||
import ShimmerLine from 'components/ui/ShimmerLine'
|
||||
import Telemetry from 'lib/telemetry'
|
||||
import { useRouter } from 'next/router'
|
||||
import MessageSelection from './MessageSelection'
|
||||
import { LogData } from './Messages.types'
|
||||
import NoChannelEmptyState from './NoChannelEmptyState'
|
||||
@@ -118,6 +120,8 @@ const MessagesTable = ({
|
||||
}: MessagesTableProps) => {
|
||||
const [focusedLog, setFocusedLog] = useState<LogData | null>(null)
|
||||
const stringData = JSON.stringify(data)
|
||||
const telemetryProps = useTelemetryProps()
|
||||
const router = useRouter()
|
||||
|
||||
useEffect(() => {
|
||||
if (!data) return
|
||||
@@ -164,6 +168,16 @@ const MessagesTable = ({
|
||||
rowHeight={40}
|
||||
headerRowHeight={0}
|
||||
onSelectedCellChange={({ rowIdx }) => {
|
||||
Telemetry.sendEvent(
|
||||
{
|
||||
category: 'realtime_inspector',
|
||||
action: 'focused-specific-message',
|
||||
label: 'realtime_inspector_results',
|
||||
},
|
||||
telemetryProps,
|
||||
router
|
||||
)
|
||||
|
||||
setFocusedLog(data[rowIdx])
|
||||
}}
|
||||
selectedRows={new Set([])}
|
||||
|
||||
Loaded 100 of 290 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user