mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
Merge branch 'master' into feat/careers-page
This commit is contained in:
commit
9e0525e9c5
1811 files changed
+58427
-121688
No files matched your search
+1
-1
@@ -1,4 +1,4 @@
|
||||
/studio/ @supabase/frontend
|
||||
/apps/www/ @supabase/frontend
|
||||
/apps/reference/ @supabase/docs
|
||||
/apps/docs/ @supabase/docs
|
||||
/spec/ @supabase/docs
|
||||
@@ -1,42 +0,0 @@
|
||||
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
|
||||
|
||||
name: Docs Compilation Check
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [master]
|
||||
paths:
|
||||
- 'apps/reference/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [16.x]
|
||||
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
# Ref: https://github.com/actions/setup-node/issues/214
|
||||
- name: Reconfigure git to use HTTP authentication
|
||||
run: >
|
||||
git config --global url."https://github.com/".insteadOf
|
||||
ssh://git@github.com/
|
||||
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: 'npm'
|
||||
|
||||
- name: Install Deps
|
||||
run: npm ci
|
||||
working-directory: ./apps/reference
|
||||
|
||||
- name: Build
|
||||
run: npm run build
|
||||
working-directory: ./apps/reference
|
||||
@@ -12,7 +12,7 @@ jobs:
|
||||
with:
|
||||
ref: master
|
||||
- uses: sobolevn/misspell-fixer-action@master
|
||||
- uses: peter-evans/create-pull-request@v2.4.4
|
||||
- uses: peter-evans/create-pull-request@v4
|
||||
env:
|
||||
ACTIONS_ALLOW_UNSECURE_COMMANDS: 'true'
|
||||
with:
|
||||
|
||||
@@ -2,6 +2,8 @@ name: Publish to Image Registry
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'studio'
|
||||
tags:
|
||||
- '*'
|
||||
workflow_dispatch:
|
||||
@@ -25,6 +27,7 @@ jobs:
|
||||
latest=false
|
||||
tags: |
|
||||
type=ref,event=tag
|
||||
type=sha,prefix={{date 'YYYYMMDD'}},enable=${{ github.ref_type == 'branch' }}
|
||||
type=raw,value=${{ inputs.version }},enable=${{ github.event_name != 'push' }}
|
||||
|
||||
- uses: docker/setup-qemu-action@v2
|
||||
@@ -49,7 +52,8 @@ jobs:
|
||||
- uses: docker/build-push-action@v3
|
||||
with:
|
||||
push: true
|
||||
context: '{{defaultContext}}:studio'
|
||||
context: '{{defaultContext}}'
|
||||
file: studio/Dockerfile
|
||||
target: production
|
||||
platforms: linux/amd64,linux/arm64
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
|
||||
+55
-153
@@ -1,45 +1,47 @@
|
||||
# Developing Supabase
|
||||
|
||||
1. [Development setup](#development-setup)
|
||||
- [Install dependencies](#install-dependencies)
|
||||
- [Fork the repository](#fork-the-repository)
|
||||
1. [Build Supabase](#build-supabase)
|
||||
- [Choose a directory](#choose-a-directory)
|
||||
1. [Start a development server](#start-a-development-server)
|
||||
- [Supabase Website](#supabase-website)
|
||||
- [Supabase Docs](#supabase-docs)
|
||||
- [Supabase Studio](#supabase-studio)
|
||||
1. [Create a pull request](#create-a-pull-request)
|
||||
1. [Getting started](#getting-started)
|
||||
- [Install dependencies](#install-dependencies)
|
||||
2. [Local development](#local-development)
|
||||
- [Fork the repository](#fork-the-repository)
|
||||
- [Clone the repo](#clone-the-repo)
|
||||
- [Running turborepo](#running-turborepo)
|
||||
- [Shared components](#shared-components)
|
||||
- [Installing packages](#installing-packages)
|
||||
3. [Create a pull request](#create-a-pull-request)
|
||||
|
||||
- [Common tasks](#common-tasks)
|
||||
- [Add a redirect](#add-a-redirect)
|
||||
- [Monorepo](#monorepo)
|
||||
- [Getting started](#getting-started)
|
||||
- [Shared components](#shared-components)
|
||||
- [Installing packages](#installing-packages)
|
||||
- [Development](#development)
|
||||
- [Community channels](#community-channels)
|
||||
|
||||
## Development setup
|
||||
## Getting started
|
||||
|
||||
Thanks for your interest in Supabase and for wanting to contribute! Before you begin, read the
|
||||
Thanks for your interest in [Supabase](https://supabase.com) and for wanting to contribute! Before you begin, read the
|
||||
[code of conduct](https://github.com/supabase/.github/blob/main/CODE_OF_CONDUCT.md) and check out the
|
||||
[existing issues](https://github.com/supabase/supabase/issues).
|
||||
This document describes how to set up your development environment to build and test Supabase.
|
||||
This document describes how to set up your development environment to build and test [Supabase](https://supabase.com).
|
||||
|
||||
### Install dependencies
|
||||
|
||||
You need to install and configure the following dependencies on your machine to build Supabase:
|
||||
You need to install and configure the following dependencies on your machine to build [Supabase](https://supabase.com):
|
||||
|
||||
- [Git](http://git-scm.com/)
|
||||
- [Node.js v16.x (LTS)](http://nodejs.org)
|
||||
- [npm](https://www.npmjs.com/) version 7+ or [Yarn](https://yarnpkg.com/)
|
||||
|
||||
## Local development
|
||||
|
||||
We are in the process of migrating this repository to monorepo, using [Turborepo](https://turborepo.org/docs).
|
||||
|
||||
Eventually, all the apps will be run using [Turborepo](https://turborepo.org/docs), which will significantly improve the developer workflow.
|
||||
|
||||
If you are working on the ([docs site](https://supabase.com/docs)), please refer to this [developers guide](https://github.com/supabase/supabase/tree/master/apps/reference/DEVELOPERS.md).
|
||||
|
||||
### Fork the repository
|
||||
|
||||
To contribute code to Supabase, you must fork the [Supabase Repository](https://github.com/supabase/supabase).
|
||||
To contribute code to [Supabase](https://supabase.com), you must fork the [Supabase Repository](https://github.com/supabase/supabase).
|
||||
|
||||
## Build Supabase
|
||||
### Clone the repo
|
||||
|
||||
1. Clone your GitHub forked repository:
|
||||
|
||||
@@ -52,104 +54,61 @@ To contribute code to Supabase, you must fork the [Supabase Repository](https://
|
||||
cd supabase
|
||||
```
|
||||
|
||||
### Choose a directory
|
||||
### Running turborepo
|
||||
|
||||
Choose if you want to work on the [Supabase Website](https://supabase.com), [Supabase Docs](https://supabase.com/docs), or [Supabase Studio](https://app.supabase.com).
|
||||
[Supabase](https://supabase.com) uses [Turborepo](https://turborepo.org/docs) to manage and run this monorepo.
|
||||
|
||||
1. Go to the [Supabase Website](https://supabase.com) directory
|
||||
1. Install the dependences in the root of the repo.
|
||||
|
||||
```sh
|
||||
cd apps/www
|
||||
npm install # install dependencies
|
||||
```
|
||||
|
||||
Go to the [Supabase Docs](https://supabase.com/docs) directory
|
||||
|
||||
2. You can then run the apps simultaneously with the following.
|
||||
```sh
|
||||
cd apps/reference
|
||||
npm run dev # start all the applications
|
||||
```
|
||||
|
||||
Go to the [Supabase Studio](https://app.supabase.com) directory
|
||||
Then visit, and edit, any of the following sites:
|
||||
|
||||
```sh
|
||||
cd studio
|
||||
```
|
||||
| Site | Directory | Scope name | Description | Local development server |
|
||||
| ---------------------------------------------- | -------------- | ---------- | ------------------------------------ | ------------------------ |
|
||||
| [supabase.com](https://supabase.com) | `/apps/www` | www | The main website | http://localhost:3000 |
|
||||
| [app.supabase.com](https://app.supabase.com) | `/studio` | studio | Studio dashboard | http://localhost:8082 |
|
||||
| [supabase.com/docs](https://supabase.com/docs) | `/apps/docs` | docs | Guides and Reference (Next.js based) | http://localhost:3001 |
|
||||
|
||||
1. Install npm/yarn dependencies:
|
||||
#### Running sites individually
|
||||
|
||||
npm
|
||||
You can run any of the sites individually by using the scope name. For example:
|
||||
|
||||
```sh
|
||||
npm install
|
||||
```
|
||||
```sh
|
||||
npm run dev:www
|
||||
```
|
||||
|
||||
or with yarn
|
||||
#### Shared components
|
||||
|
||||
```sh
|
||||
yarn install
|
||||
```
|
||||
The monorepo has a set of shared components under `/packages`:
|
||||
|
||||
## Start a development server
|
||||
- `/packages/common`: Common React code, shared between all sites.
|
||||
- `/packages/config`: All shared config
|
||||
- `/packages/spec`: Generates documentation using spec files.
|
||||
- `/packages/tsconfig`: Shared Typescript settings
|
||||
|
||||
To debug code and to see your changes in real time, it is often useful to have a local HTTP server. Click one of the three links below to choose which development server you want to start.
|
||||
#### Installing packages
|
||||
|
||||
- [Supabase Website](#supabase-website)
|
||||
- [Supabase Docs](#supabase-docs)
|
||||
- [Supabase Studio](#supabase-studio)
|
||||
Installing a package with NPM workspaces requires you to add the `-w` flag to tell NPM which workspace you want to install into. Do not install dependencies in their local folder, install them from the route using the `-w` flag.
|
||||
|
||||
### Supabase Website
|
||||
The format is: `npm install <package name> -w=<workspace to install in>`.
|
||||
|
||||
The website is moving to a new monorepo setup. See the [Monorepo](#monorepo) section below.
|
||||
For example:
|
||||
|
||||
### Supabase Docs
|
||||
- `npm install react -w common`: installs into `./packages/common`
|
||||
- `npm install react -w www`: installs into `./apps/www`
|
||||
- `npm install react -w studio`: installs into `./studio`
|
||||
|
||||
1. Build development server
|
||||
You do not need to install `devDependencies` in each workspace. These can all be installed in the root package.
|
||||
|
||||
npm
|
||||
|
||||
```sh
|
||||
npm run build
|
||||
```
|
||||
|
||||
or with yarn
|
||||
|
||||
```sh
|
||||
yarn build
|
||||
```
|
||||
|
||||
1. Start development server
|
||||
|
||||
npm
|
||||
|
||||
```sh
|
||||
npm run start
|
||||
```
|
||||
|
||||
or with yarn
|
||||
|
||||
```sh
|
||||
yarn start
|
||||
```
|
||||
|
||||
1. Access the local server in your web browser at http://localhost:3010/docs.
|
||||
|
||||
### Supabase Studio
|
||||
|
||||
1. Start development server
|
||||
|
||||
npm
|
||||
|
||||
```sh
|
||||
npm run dev
|
||||
```
|
||||
|
||||
or with yarn
|
||||
|
||||
```sh
|
||||
yarn dev
|
||||
```
|
||||
|
||||
1. Access the local server in your web browser at http://localhost:8082/.
|
||||
See the [Supabase Studio readme](./studio/README.md) for more information.
|
||||
---
|
||||
|
||||
## Create a pull request
|
||||
|
||||
@@ -165,63 +124,6 @@ Did you have an issue, like a merge conflict, or don't know how to open a pull r
|
||||
|
||||
Create a new entry in the [`redirects.js`](https://github.com/supabase/supabase/blob/master/apps/www/lib/redirects.js) file in our main site.
|
||||
|
||||
## Monorepo
|
||||
|
||||
We are in the process of migrating this repository to monorepo, using Turborepo.
|
||||
Eventually, the docs and the Studio will be run using Turborepo, which will significantly improve the developer workflow.
|
||||
You must be using NPM 7 or higher.
|
||||
|
||||
### Getting started
|
||||
|
||||
```sh
|
||||
npm install # install dependencies
|
||||
npm run dev # start all the applications
|
||||
```
|
||||
|
||||
Then edit and visit any of the following sites:
|
||||
|
||||
Site | Directory | Description | Local development server
|
||||
---- | --------- | ----------- | ------------------------
|
||||
[supabase.com](https://supabase.com) | `/apps/www` | The main website | http://localhost:3000
|
||||
[supabase.com/docs](https://supabase.com/docs) | `apps/reference` | Guides and Reference documentation | http://localhost:3010/docs
|
||||
[POC] Community forum | `/apps/temp-community-forum` | GitHub Discussions in a Next.js site | http://localhost:3002
|
||||
[POC] DEV articles site | `/apps/temp-community-tutorials` | A Next.js site for our DEV articles (which community members can write) | http://localhost:3003
|
||||
|
||||
### Shared components
|
||||
|
||||
The monorepo has a set of shared components under `/packages`:
|
||||
|
||||
- `/packages/common`: Common React code, shared between all sites.
|
||||
- `/packages/config`: All shared config
|
||||
- `/packages/spec`: Generates documentation using spec files.
|
||||
- `/packages/tsconfig`: Shared Typescript settings
|
||||
- `/packages/ui`: Shared UI components (formerly @supabase/ui)
|
||||
|
||||
To use these 'packages', or any of their components from a Next.JS app, you must use `next-transpile-modules` in the `next.config.js` file. This looks like:
|
||||
|
||||
```tsx
|
||||
// next.config.js
|
||||
const withTM = require('next-transpile-modules')(['ui', 'common'])
|
||||
module.exports = withTM({})
|
||||
```
|
||||
|
||||
### Installing packages
|
||||
|
||||
Installing a package with NPM workspaces requires you to add the `-w` flag to tell NPM which workspace you want to install into.
|
||||
|
||||
The format is: `npm install <package name> -w=<workspace to install in>`.
|
||||
|
||||
For example:
|
||||
|
||||
- `npm install @supabase/ui -w common`: installs into `./packages/common`
|
||||
- `npm install @supabase/ui -w www`: installs into `./apps/www`
|
||||
|
||||
You do not need to install `devDependencies` in each workspace. These can all be installed in the root package.
|
||||
|
||||
### Development
|
||||
|
||||
`npm run dev`
|
||||
|
||||
---
|
||||
|
||||
## Community channels
|
||||
|
||||
@@ -107,6 +107,15 @@ Our approach for client libraries is modular. Each sub-library is a standalone i
|
||||
<td><a href="https://github.com/supabase/realtime-js" target="_blank" rel="noopener noreferrer">realtime-js</a></td>
|
||||
<td><a href="https://github.com/supabase/storage-js" target="_blank" rel="noopener noreferrer">storage-js</a></td>
|
||||
<td><a href="https://github.com/supabase/functions-js" target="_blank" rel="noopener noreferrer">functions-js</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Flutter</td>
|
||||
<td><a href="https://github.com/supabase/supabase-flutter" target="_blank" rel="noopener noreferrer">supabase-flutter</a></td>
|
||||
<td><a href="https://github.com/supabase/postgrest-dart" target="_blank" rel="noopener noreferrer">postgrest-dart</a></td>
|
||||
<td><a href="https://github.com/supabase/gotrue-dart" target="_blank" rel="noopener noreferrer">gotrue-dart</a></td>
|
||||
<td><a href="https://github.com/supabase/realtime-dart" target="_blank" rel="noopener noreferrer">realtime-dart</a></td>
|
||||
<td><a href="https://github.com/supabase/storage-dart" target="_blank" rel="noopener noreferrer">storage-dart</a></td>
|
||||
<td><a href="https://github.com/supabase/functions-dart" target="_blank" rel="noopener noreferrer">functions-dart</a></td>
|
||||
</tr>
|
||||
<th colspan="7">💚 Community 💚</th>
|
||||
<tr>
|
||||
@@ -118,20 +127,11 @@ Our approach for client libraries is modular. Each sub-library is a standalone i
|
||||
<td><a href="https://github.com/supabase-community/storage-csharp" target="_blank" rel="noopener noreferrer">storage-csharp</a></td>
|
||||
<td><a href="https://github.com/supabase-community/functions-csharp" target="_blank" rel="noopener noreferrer">functions-csharp</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Flutter</td>
|
||||
<td><a href="https://github.com/supabase/supabase-flutter" target="_blank" rel="noopener noreferrer">supabase-flutter</a></td>
|
||||
<td><a href="https://github.com/supabase/postgrest-dart" target="_blank" rel="noopener noreferrer">postgrest-dart</a></td>
|
||||
<td><a href="https://github.com/supabase/gotrue-dart" target="_blank" rel="noopener noreferrer">gotrue-dart</a></td>
|
||||
<td><a href="https://github.com/supabase/realtime-dart" target="_blank" rel="noopener noreferrer">realtime-dart</a></td>
|
||||
<td><a href="https://github.com/supabase/storage-dart" target="_blank" rel="noopener noreferrer">storage-dart</a></td>
|
||||
<td><a href="https://github.com/supabase-community/functions-dart" target="_blank" rel="noopener noreferrer">functions-dart</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Go</td>
|
||||
<td>-</td>
|
||||
<td><a href="https://github.com/supabase-community/postgrest-go" target="_blank" rel="noopener noreferrer">postgrest-go</a></td>
|
||||
<td>-</td>
|
||||
<td><a href="https://github.com/supabase-community/gotrue-go" target="_blank" rel="noopener noreferrer">gotrue-go</a></td>
|
||||
<td>-</td>
|
||||
<td><a href="https://github.com/supabase-community/storage-go" target="_blank" rel="noopener noreferrer">storage-go</a></td>
|
||||
<td><a href="https://github.com/supabase-community/functions-go" target="_blank" rel="noopener noreferrer">functions-go</a></td>
|
||||
@@ -147,12 +147,12 @@ Our approach for client libraries is modular. Each sub-library is a standalone i
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Kotlin</td>
|
||||
<td>-</td>
|
||||
<td><a href="https://github.com/supabase-community/supabase-kt" target="_blank" rel="noopener noreferrer">supabase-kt</a></td>
|
||||
<td><a href="https://github.com/supabase-community/postgrest-kt" target="_blank" rel="noopener noreferrer">postgrest-kt</a></td>
|
||||
<td><a href="https://github.com/supabase-community/gotrue-kt" target="_blank" rel="noopener noreferrer">gotrue-kt</a></td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td><a href="https://github.com/supabase-community/supabase-kt/tree/master/Realtime" target="_blank" rel="noopener noreferrer">realtime-kt</a></td>
|
||||
<td><a href="https://github.com/supabase-community/supabase-kt/tree/master/Storage" target="_blank" rel="noopener noreferrer">storage-kt</a></td>
|
||||
<td><a href="https://github.com/supabase-community/supabase-kt/tree/master/Functions" target="_blank" rel="noopener noreferrer">functions-kt</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Python</td>
|
||||
@@ -188,7 +188,16 @@ Our approach for client libraries is modular. Each sub-library is a standalone i
|
||||
<td><a href="https://github.com/supabase-community/gotrue-swift" target="_blank" rel="noopener noreferrer">gotrue-swift</a></td>
|
||||
<td><a href="https://github.com/supabase-community/realtime-swift" target="_blank" rel="noopener noreferrer">realtime-swift</a></td>
|
||||
<td><a href="https://github.com/supabase-community/storage-swift" target="_blank" rel="noopener noreferrer">storage-swift</a></td>
|
||||
<td>-</td>
|
||||
<td><a href="https://github.com/supabase-community/functions-swift" target="_blank" rel="noopener noreferrer">functions-swift</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Godot Engine (GDScript)</td>
|
||||
<td><a href="https://github.com/supabase-community/godot-engine.supabase" target="_blank" rel="noopener noreferrer">supabase-gdscript</a></td>
|
||||
<td><a href="https://github.com/supabase-community/postgrest-gdscript" target="_blank" rel="noopener noreferrer">postgrest-gdscript</a></td>
|
||||
<td><a href="https://github.com/supabase-community/gotrue-gdscript" target="_blank" rel="noopener noreferrer">gotrue-gdscript</a></td>
|
||||
<td><a href="https://github.com/supabase-community/realtime-gdscript" target="_blank" rel="noopener noreferrer">realtime-gdscript</a></td>
|
||||
<td><a href="https://github.com/supabase-community/storage-gdscript" target="_blank" rel="noopener noreferrer">storage-gdscript</a></td>
|
||||
<td><a href="https://github.com/supabase-community/functions-gdscript" target="_blank" rel="noopener noreferrer">functions-gdscript</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
File renamed without changes.
File renamed without changes.
@@ -42,4 +42,4 @@ We use documentation specifications which can be used to generate human-readable
|
||||
- CLISpec (custom to Supabase): for CLI commands and usage.
|
||||
|
||||
The benefit of using custom specifications is that we can generate many other types from a strict schema (eg, HTML and manpages).
|
||||
It also means that we can switch any documentation system we want. On this site we use Docusaurus, but in Supabase's official website we use a custom React site and expose only a subset of the available API for each tool.
|
||||
It also means that we can switch any documentation system we want. On this site we use Next.JS, but in Supabase's official website we use a custom React site and expose only a subset of the available API for each tool.
|
||||
@@ -0,0 +1,51 @@
|
||||
import { FC } from 'react'
|
||||
import { IconInfo, IconHelpCircle, IconAlertTriangle } from 'ui'
|
||||
|
||||
interface Props {
|
||||
type: 'note' | 'tip' | 'info' | 'caution' | 'danger'
|
||||
label?: string
|
||||
children: any
|
||||
}
|
||||
|
||||
const Admonition: FC<Props> = ({ type = 'note', label, children }) => {
|
||||
return (
|
||||
<div
|
||||
className={[
|
||||
'shadow p-4 rounded border-l-[5px] space-y-2 my-4',
|
||||
`${
|
||||
type === 'note'
|
||||
? 'bg-scale-400 border-scale-800'
|
||||
: type === 'info'
|
||||
? 'bg-scale-500 border-scale-800'
|
||||
: type === 'tip'
|
||||
? 'bg-brand-300 border-brand-800'
|
||||
: type === 'caution'
|
||||
? 'bg-yellow-400 border-yellow-800'
|
||||
: type === 'danger'
|
||||
? 'bg-red-500 border-red-800'
|
||||
: 'bg-scale-500 border-scale-800'
|
||||
}`,
|
||||
].join(' ')}
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
{type === 'note' ? (
|
||||
<IconInfo className="text-scale-1200" size={18} strokeWidth={1.5} />
|
||||
) : type === 'info' ? (
|
||||
<IconInfo className="text-scale-1200" size={18} strokeWidth={1.5} />
|
||||
) : type === 'tip' ? (
|
||||
<IconHelpCircle className="text-scale-1200" size={18} strokeWidth={1.5} />
|
||||
) : type === 'caution' ? (
|
||||
<IconAlertTriangle className="text-scale-1200" size={18} strokeWidth={1.5} />
|
||||
) : type === 'danger' ? (
|
||||
<IconAlertTriangle className="text-scale-1200" size={18} strokeWidth={1.5} />
|
||||
) : (
|
||||
<IconInfo className="text-scale-1200" size={18} strokeWidth={1.5} />
|
||||
)}
|
||||
<p className="text-sm text-scale-1200 uppercase my-0 font-bold">{label || type}</p>
|
||||
</div>
|
||||
<div className="admonition-content text-scale-1200 text-base space-y-1">{children}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Admonition
|
||||
@@ -0,0 +1,53 @@
|
||||
import providers from '../data/authProviders'
|
||||
import ButtonCard from './ButtonCard'
|
||||
|
||||
export default function AuthProviders() {
|
||||
return (
|
||||
<div className="grid md:grid-cols-12 gap-4">
|
||||
{providers.map((x) => (
|
||||
<div key={x.name} className="col-span-6">
|
||||
<ButtonCard to={x.href} title={x.name}>
|
||||
<div className="px-6 py-4">
|
||||
<div className="flex justify-between">
|
||||
<p className="mt-0">{x.name}</p>
|
||||
<p className="mt-0">
|
||||
{x.official ? (
|
||||
<span className={`badge badge--official`}>Official</span>
|
||||
) : (
|
||||
<span className={`badge badge--unofficial`}>Unofficial</span>
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 5 }}>
|
||||
<div
|
||||
className="code-block"
|
||||
style={{
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
fontSize: '0.7rem',
|
||||
}}
|
||||
>
|
||||
<span>Platform:</span>
|
||||
<span>{x.platform.toString()}</span>
|
||||
</div>
|
||||
<div
|
||||
className="code-block"
|
||||
style={{
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
fontSize: '0.7rem',
|
||||
}}
|
||||
>
|
||||
<span>Self-Hosted:</span>
|
||||
<span>{x.selfHosted.toString()}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ButtonCard>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import React, { FC, ReactNode } from 'react'
|
||||
import Link from 'next/link'
|
||||
import Image from 'next/image'
|
||||
|
||||
interface Props {
|
||||
title: string
|
||||
description?: string
|
||||
to: string
|
||||
icon?: string | any
|
||||
children?: any
|
||||
layout?: 'vertical' | 'horizontal'
|
||||
}
|
||||
|
||||
const ButtonCard: FC<Props> = ({
|
||||
children = undefined,
|
||||
icon = undefined,
|
||||
title,
|
||||
description = '',
|
||||
to,
|
||||
layout = 'vertical',
|
||||
}) => {
|
||||
return (
|
||||
<Link href={to}>
|
||||
<a
|
||||
className={[
|
||||
'h-full block shadow-none bg-scale-300 rounded transition',
|
||||
'border border-transparent hover:border-scale-600',
|
||||
].join('')}
|
||||
>
|
||||
{children ? (
|
||||
children
|
||||
) : (
|
||||
<div
|
||||
className={[
|
||||
'px-6 py-4 gap-x-4 gap-y-2 flex',
|
||||
`${layout === 'vertical' ? 'flex-col' : 'items-center'}`,
|
||||
].join(' ')}
|
||||
>
|
||||
{icon && typeof icon == 'string' ? (
|
||||
<div className="w-[24px] h-[24px]">
|
||||
<Image className="m-0" src={icon} width={24} height={24} alt={title} />
|
||||
</div>
|
||||
) : (
|
||||
icon
|
||||
)}
|
||||
<h3 className="my-0 text-base">{title}</h3>
|
||||
<p className="my-0 text-sm">{description}</p>
|
||||
</div>
|
||||
)}
|
||||
</a>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
export default ButtonCard
|
||||
@@ -0,0 +1,137 @@
|
||||
import { FC } from 'react'
|
||||
import CopyToClipboard from 'react-copy-to-clipboard'
|
||||
import { Light as SyntaxHighlighter } from 'react-syntax-highlighter'
|
||||
import monokaiCustomTheme from './CodeBlock.utils'
|
||||
import { Button, IconCheck, IconCopy } from 'ui'
|
||||
|
||||
import js from 'react-syntax-highlighter/dist/cjs/languages/hljs/javascript'
|
||||
import ts from 'react-syntax-highlighter/dist/cjs/languages/hljs/typescript'
|
||||
import py from 'react-syntax-highlighter/dist/cjs/languages/hljs/python'
|
||||
import sql from 'react-syntax-highlighter/dist/cjs/languages/hljs/sql'
|
||||
import bash from 'react-syntax-highlighter/dist/cjs/languages/hljs/bash'
|
||||
import dart from 'react-syntax-highlighter/dist/cjs/languages/hljs/dart'
|
||||
|
||||
import { useState } from 'react'
|
||||
import { useTheme } from '../Providers'
|
||||
|
||||
interface Props {
|
||||
title?: string
|
||||
language: 'js' | 'jsx' | 'sql' | 'py' | 'bash' | 'ts' | 'dart'
|
||||
linesToHighlight?: number[]
|
||||
hideCopy?: boolean
|
||||
hideLineNumbers?: boolean
|
||||
className?: string
|
||||
value?: string
|
||||
children?: string
|
||||
}
|
||||
|
||||
const CodeBlock: FC<Props> = ({
|
||||
title,
|
||||
language,
|
||||
linesToHighlight = [],
|
||||
className,
|
||||
value,
|
||||
children,
|
||||
hideCopy = false,
|
||||
hideLineNumbers = false,
|
||||
}) => {
|
||||
const { isDarkMode } = useTheme()
|
||||
const monokaiTheme = monokaiCustomTheme(isDarkMode)
|
||||
|
||||
const [copied, setCopied] = useState(false)
|
||||
|
||||
const handleCopy = () => {
|
||||
setCopied(true)
|
||||
setTimeout(() => {
|
||||
setCopied(false)
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
let lang = language ? language : className ? className.replace('language-', '') : 'js'
|
||||
// force jsx to be js highlighted
|
||||
if (lang === 'jsx') lang = 'js'
|
||||
SyntaxHighlighter.registerLanguage('js', js)
|
||||
SyntaxHighlighter.registerLanguage('ts', ts)
|
||||
SyntaxHighlighter.registerLanguage('py', py)
|
||||
SyntaxHighlighter.registerLanguage('sql', sql)
|
||||
SyntaxHighlighter.registerLanguage('bash', bash)
|
||||
SyntaxHighlighter.registerLanguage('dart', dart)
|
||||
|
||||
const large = false
|
||||
// don't show line numbers if bash == lang
|
||||
const showLineNumbers = hideLineNumbers || lang !== 'bash'
|
||||
|
||||
return (
|
||||
<div className="relative my-2 max-w-[90vw] md:max-w-none overflow-auto">
|
||||
{title && (
|
||||
<div className="rounded-t-md bg-scale-300 py-2 px-4 border-b border-scale-500 text-blue-1100 font-sans">
|
||||
{title.replace(/%20/g, ' ')}
|
||||
</div>
|
||||
)}
|
||||
{className ? (
|
||||
<SyntaxHighlighter
|
||||
language={lang}
|
||||
wrapLines={true}
|
||||
style={monokaiTheme}
|
||||
className={[
|
||||
'code-block border p-4 w-full !my-0 !bg-scale-300',
|
||||
`${!title ? '!rounded-md' : '!rounded-t-none !rounded-b-md'}`,
|
||||
`${!showLineNumbers ? 'pl-6' : ''}`,
|
||||
].join(' ')}
|
||||
customStyle={{
|
||||
fontSize: large ? 18 : 13,
|
||||
lineHeight: large ? 1.5 : 1.4,
|
||||
}}
|
||||
showLineNumbers={showLineNumbers}
|
||||
lineProps={(lineNumber) => {
|
||||
if (linesToHighlight.includes(lineNumber)) {
|
||||
return {
|
||||
style: { display: 'block', backgroundColor: 'var(--colors-scale6)' },
|
||||
}
|
||||
}
|
||||
return {}
|
||||
}}
|
||||
lineNumberContainerStyle={{
|
||||
paddingTop: '128px',
|
||||
}}
|
||||
lineNumberStyle={{
|
||||
minWidth: '44px',
|
||||
paddingLeft: '4px',
|
||||
paddingRight: '4px',
|
||||
marginRight: '12px',
|
||||
color: '#828282',
|
||||
textAlign: 'center',
|
||||
fontSize: large ? 14 : 12,
|
||||
paddingTop: '4px',
|
||||
paddingBottom: '4px',
|
||||
}}
|
||||
>
|
||||
{(value || children)?.trimEnd()}
|
||||
</SyntaxHighlighter>
|
||||
) : (
|
||||
<code>{value || children}</code>
|
||||
)}
|
||||
{!hideCopy && (value || children) && className ? (
|
||||
<div
|
||||
className={[
|
||||
'absolute right-2',
|
||||
`${isDarkMode ? 'dark' : ''}`,
|
||||
`${!title ? 'top-2' : 'top-[3.25rem]'}`,
|
||||
].join(' ')}
|
||||
>
|
||||
<CopyToClipboard text={value || children}>
|
||||
<Button
|
||||
type="default"
|
||||
icon={copied ? <IconCheck /> : <IconCopy />}
|
||||
onClick={() => handleCopy()}
|
||||
>
|
||||
{copied ? 'Copied' : ''}
|
||||
</Button>
|
||||
</CopyToClipboard>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default CodeBlock
|
||||
+29
@@ -1,3 +1,32 @@
|
||||
// https://github.com/euank/node-parse-numeric-range/blob/master/index.js
|
||||
export function parseNumericRange(string) {
|
||||
let res = []
|
||||
let m
|
||||
|
||||
for (let str of string.split(',').map((str) => str.trim())) {
|
||||
// just a number
|
||||
if (/^-?\d+$/.test(str)) {
|
||||
res.push(parseInt(str, 10))
|
||||
} else if ((m = str.match(/^(-?\d+)(-|\.\.\.?|\u2025|\u2026|\u22EF)(-?\d+)$/))) {
|
||||
// 1-5 or 1..5 (equivalent) or 1...5 (doesn't include 5)
|
||||
let [_, lhs, sep, rhs] = m
|
||||
|
||||
if (lhs && rhs) {
|
||||
lhs = parseInt(lhs)
|
||||
rhs = parseInt(rhs)
|
||||
const incr = lhs < rhs ? 1 : -1
|
||||
|
||||
// Make it inclusive by moving the right 'stop-point' away by one.
|
||||
if (sep === '-' || sep === '..' || sep === '\u2025') rhs += incr
|
||||
|
||||
for (let i = lhs; i !== rhs; i += incr) res.push(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
const monokaiCustomTheme = (isDarkMode) => {
|
||||
return {
|
||||
hljs: {
|
||||
@@ -0,0 +1,79 @@
|
||||
// Check if heading has custom anchor first, before forming the anchor based on the title
|
||||
export const getAnchor = (text: any): string | undefined => {
|
||||
if (typeof text === 'object') {
|
||||
if (Array.isArray(text)) {
|
||||
const customAnchor = text.find(
|
||||
(x) => typeof x === 'string' && x.includes('[#') && x.endsWith(']')
|
||||
)
|
||||
if (customAnchor !== undefined) return customAnchor.slice(2, customAnchor.indexOf(']'))
|
||||
|
||||
const formattedText = text
|
||||
.map((x) => {
|
||||
if (typeof x !== 'string') return x.props.children
|
||||
else return x.trim()
|
||||
})
|
||||
.map((x) => {
|
||||
if (typeof x !== 'string') return x
|
||||
else
|
||||
return x
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9- ]/g, '')
|
||||
.replace(/[ ]/g, '-')
|
||||
})
|
||||
|
||||
return formattedText.join('-').toLowerCase()
|
||||
} else {
|
||||
const anchor = text.props.children
|
||||
if (typeof anchor === 'string') {
|
||||
return anchor
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9- ]/g, '')
|
||||
.replace(/[ ]/g, '-')
|
||||
}
|
||||
return anchor
|
||||
}
|
||||
} else if (typeof text === 'string') {
|
||||
if (text.includes('[#') && text.endsWith(']')) {
|
||||
return text.slice(text.indexOf('[#') + 2, text.indexOf(']'))
|
||||
} else {
|
||||
return text
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9- ]/g, '')
|
||||
.replace(/[ ]/g, '-')
|
||||
}
|
||||
} else {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
export const removeAnchor = (text: any) => {
|
||||
if (typeof text === 'object' && Array.isArray(text)) {
|
||||
return text.filter((x) => !(typeof x === 'string' && x.includes('[#') && x.endsWith(']')))
|
||||
} else if (typeof text === 'string') {
|
||||
if (text.indexOf('[#') > 0) return text.slice(0, text.indexOf('[#'))
|
||||
else return text
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
export const highlightSelectedTocItem = (id: string) => {
|
||||
const tocMenuItems = document.querySelectorAll('.toc-menu a')
|
||||
|
||||
// find any currently active items and remove them
|
||||
const currentActiveItem = document.querySelector('.toc-menu .toc__menu-item--active')
|
||||
currentActiveItem?.classList.remove('toc__menu-item--active')
|
||||
|
||||
// Add active class to the current item
|
||||
tocMenuItems.forEach((item) => {
|
||||
// @ts-ignore
|
||||
if (item.href.split('#')[1] === id) {
|
||||
item.classList.add('toc__menu-item--active')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// find any currently active items and remove them on route change
|
||||
export const unHighlightSelectedTocItems = () => {
|
||||
const currentActiveItem = document.querySelector('.toc-menu .toc__menu-item--active')
|
||||
currentActiveItem?.classList.remove('toc__menu-item--active')
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import {
|
||||
getAnchor,
|
||||
removeAnchor,
|
||||
highlightSelectedTocItem,
|
||||
unHighlightSelectedTocItems,
|
||||
} from './CustomHTMLElements.utils'
|
||||
import { useInView } from 'react-intersection-observer'
|
||||
|
||||
const Heading = ({ tag, children }) => {
|
||||
const HeadingTag = `${tag}` as any
|
||||
const anchor = getAnchor(children)
|
||||
const link = `#${anchor}`
|
||||
|
||||
// check if current heading is in view, update TOC active item accordingly
|
||||
// [Joshen] Ideally we highlight the section in the TOC when it's at the top of the page
|
||||
// much like when we click on the item in the TOC itself, the rootMargin fix is insufficient
|
||||
const { ref } = useInView({
|
||||
threshold: 1,
|
||||
onChange: (inView, entry) => {
|
||||
if (window.scrollY === 0) unHighlightSelectedTocItems()
|
||||
if (inView) highlightSelectedTocItem(entry.target.id)
|
||||
},
|
||||
})
|
||||
|
||||
return (
|
||||
<HeadingTag id={anchor} ref={ref} className="group scroll-mt-24">
|
||||
{removeAnchor(children)}
|
||||
{anchor && (
|
||||
<a href={link} className="ml-2 opacity-0 group-hover:opacity-100 transition">
|
||||
#
|
||||
</a>
|
||||
)}
|
||||
</HeadingTag>
|
||||
)
|
||||
}
|
||||
export default Heading
|
||||
@@ -0,0 +1,11 @@
|
||||
const InlineCodeTag = ({ children }) => {
|
||||
// If children isn't a string, just return it as is, just in case
|
||||
if (typeof children !== 'string') return children
|
||||
|
||||
// check the length of the string inside the <code> tag
|
||||
// if it's fewer than 70 characters, add a white-space: pre so it doesn't wrap
|
||||
const classes = children.length < 70 ? 'short-inline-codeblock' : ''
|
||||
|
||||
return <code className={classes}>{children}</code>
|
||||
}
|
||||
export default InlineCodeTag
|
||||
@@ -0,0 +1,3 @@
|
||||
import Heading from './Heading'
|
||||
|
||||
export { Heading }
|
||||
@@ -7,9 +7,12 @@ import { DocSearchModal } from '@docsearch/react'
|
||||
import clsx from 'clsx'
|
||||
import { useActionKey } from '~/hooks/useActionKey'
|
||||
|
||||
const INDEX_NAME = 'tailwindcss_dev'
|
||||
const API_KEY = '5fc87cef58bb80203d2207578309fab6'
|
||||
const APP_ID = 'KNPXZI5B0M'
|
||||
// [Joshen] We're currently using this over Algolia search for the time being
|
||||
// Refer to the comment in Navigation/AlgoliaSearch for more information about this
|
||||
|
||||
const INDEX_NAME = process.env.NEXT_PUBLIC_ALGOLIA_INDEX_NAME
|
||||
const API_KEY = process.env.NEXT_PUBLIC_ALGOLIA_SEARCH_API_KEY
|
||||
const APP_ID = process.env.NEXT_PUBLIC_ALGOLIA_APP_ID
|
||||
|
||||
const SearchContext = createContext(null)
|
||||
|
||||
@@ -64,10 +67,6 @@ export function SearchProvider({ children }: any) {
|
||||
// @ts-ignore
|
||||
initialQuery={initialQuery}
|
||||
initialScrollY={window.scrollY}
|
||||
searchParameters={{
|
||||
facetFilters: 'version:v3',
|
||||
distinct: 1,
|
||||
}}
|
||||
placeholder="Search documentation"
|
||||
onClose={onClose}
|
||||
indexName={INDEX_NAME}
|
||||
@@ -75,11 +74,14 @@ export function SearchProvider({ children }: any) {
|
||||
appId={APP_ID}
|
||||
// @ts-ignore
|
||||
navigator={{
|
||||
navigate({ suggestionUrl }) {
|
||||
navigate({ itemUrl }) {
|
||||
setIsOpen(false)
|
||||
router.push(suggestionUrl)
|
||||
router.push(itemUrl)
|
||||
},
|
||||
}}
|
||||
getMissingResultsUrl={({ query }) => {
|
||||
return `https://github.com/supabase/supabase/issues/new?title=Unable+to+search+docs+with+query:+${query}`
|
||||
}}
|
||||
hitComponent={Hit}
|
||||
transformItems={(items) => {
|
||||
return items.map((item, index) => {
|
||||
@@ -0,0 +1,35 @@
|
||||
import React, { useState } from 'react'
|
||||
import extensions from '../data/extensions.json'
|
||||
|
||||
export default function Extensions() {
|
||||
const [filter, setFilter] = useState('')
|
||||
return (
|
||||
<>
|
||||
<div className="mb-8 grid">
|
||||
<label className="text-xs mb-2">Filter extensions</label>
|
||||
<input
|
||||
type="text"
|
||||
className="border text-gray-200"
|
||||
placeholder="Extension name"
|
||||
onChange={(e) => setFilter(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid sm:grid-cols-2 gap-4">
|
||||
{extensions
|
||||
.filter((x) => x.name.indexOf(filter) >= 0)
|
||||
.map((extension) => (
|
||||
<div className={' my-2 px-2'} key={extension.name}>
|
||||
<div className="border rounded-sm p-4">
|
||||
<h3 className="m-0">
|
||||
<code className="text-sm">{extension.name}</code>
|
||||
</h3>
|
||||
<p className=" mt-4">
|
||||
{extension.comment.charAt(0).toUpperCase() + extension.comment.slice(1)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import Head from 'next/head'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
const Favicons = () => {
|
||||
const { basePath } = useRouter()
|
||||
return (
|
||||
<Head>
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
sizes="180x180"
|
||||
href={`${basePath}/favicon/apple-touch-icon.png`}
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="32x32"
|
||||
href={`${basePath}/favicon/favicon-32x32.png`}
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="16x16"
|
||||
href={`${basePath}/favicon/favicon-16x16.png`}
|
||||
/>
|
||||
<link rel="manifest" href={`${basePath}/favicon/site.webmanifest`} />
|
||||
{/* <link rel="mask-icon" href={`${basePath}/favicon/safari-pinned-tab.svg`} color="#333333" /> */}
|
||||
<link rel="shortcut icon" href={`${basePath}/favicon/favicon.ico`} />
|
||||
<meta name="msapplication-TileColor" content="#1E1E1E" />
|
||||
<meta name="msapplication-config" content={`${basePath}/favicon/browserconfig.xml`} />
|
||||
<meta name="theme-color" content="#1E1E1E" />
|
||||
<link rel="alternate" type="application/rss+xml" href={`${basePath}/feed.xml`} />
|
||||
<link rel="icon" type="image/png" href={`${basePath}/favicon/favicon.ico`} />
|
||||
<link rel="apple-touch-icon" href={`${basePath}/favicon/favicon.ico`} />
|
||||
</Head>
|
||||
)
|
||||
}
|
||||
|
||||
export default Favicons
|
||||
File renamed without changes.
@@ -1,10 +1,9 @@
|
||||
import FooterLinks from 'data/footer.json'
|
||||
import SectionContainer from './SectionContainer'
|
||||
import DarkModeToggle from './DarkModeToggle'
|
||||
import Link from 'next/link'
|
||||
import { useTheme } from './Providers'
|
||||
import { Badge } from 'ui'
|
||||
import Link from 'next/link'
|
||||
import Image from 'next/image'
|
||||
import FooterLinks from 'data/footer.json'
|
||||
import DarkModeToggle from './DarkModeToggle'
|
||||
import { useTheme } from '../Providers'
|
||||
import * as supabaseLogoWordmarkDark from 'common/assets/images/supabase-logo-wordmark--dark.png'
|
||||
import * as supabaseLogoWordmarkLight from 'common/assets/images/supabase-logo-wordmark--light.png'
|
||||
|
||||
@@ -19,7 +18,7 @@ const Footer = () => {
|
||||
<h2 id="footerHeading" className="sr-only">
|
||||
Footer
|
||||
</h2>
|
||||
<SectionContainer>
|
||||
<div className="sm:py-18 container relative mx-auto px-6 py-16 md:py-24 lg:px-16 lg:py-24 xl:px-20">
|
||||
<div className="xl:grid xl:grid-cols-3 xl:gap-8">
|
||||
<div className="space-y-8 xl:col-span-1">
|
||||
<Link href="#" as="/">
|
||||
@@ -126,7 +125,7 @@ const Footer = () => {
|
||||
<small className="small">© Supabase Inc</small>
|
||||
<DarkModeToggle />
|
||||
</div>
|
||||
</SectionContainer>
|
||||
</div>
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
import ButtonCard from './ButtonCard'
|
||||
import { useTheme } from '~/components/Providers'
|
||||
|
||||
const Frameworks = () => {
|
||||
const { isDarkMode } = useTheme()
|
||||
|
||||
const frameworks = [
|
||||
{
|
||||
name: 'Angular',
|
||||
logo: {
|
||||
light: '/docs/img/libraries/angular-icon.svg',
|
||||
dark: '/docs/img/libraries/angular-icon.svg',
|
||||
},
|
||||
href: '/guides/with-angular',
|
||||
},
|
||||
{
|
||||
name: 'Expo',
|
||||
logo: {
|
||||
light: '/docs/img/libraries/expo-icon.svg',
|
||||
dark: '/docs/img/libraries/expo-icon-dark.svg',
|
||||
},
|
||||
href: '/guides/with-expo',
|
||||
},
|
||||
{
|
||||
name: 'Flutter',
|
||||
logo: {
|
||||
light: '/docs/img/libraries/flutter-icon.svg',
|
||||
dark: '/docs/img/libraries/flutter-icon.svg',
|
||||
},
|
||||
href: '/guides/with-flutter',
|
||||
},
|
||||
{
|
||||
name: 'JavaScript',
|
||||
logo: {
|
||||
light: '/docs/img/libraries/javascript-icon.svg',
|
||||
dark: '/docs/img/libraries/javascript-icon.svg',
|
||||
},
|
||||
href: '/reference/javascript/installing#javascript',
|
||||
},
|
||||
{
|
||||
name: 'Next.js',
|
||||
logo: {
|
||||
light: '/docs/img/libraries/nextjs-light-icon.svg',
|
||||
dark: '/docs/img/libraries/nextjs-dark-icon.svg',
|
||||
},
|
||||
href: '/guides/with-nextjs',
|
||||
},
|
||||
{
|
||||
name: 'React',
|
||||
logo: {
|
||||
light: '/docs/img/libraries/react-icon.svg',
|
||||
dark: '/docs/img/libraries/react-icon.svg',
|
||||
},
|
||||
href: '/guides/with-react',
|
||||
},
|
||||
{
|
||||
name: 'RedwoodJS',
|
||||
logo: {
|
||||
light: '/docs/img/libraries/redwoodjs-icon.svg',
|
||||
dark: '/docs/img/libraries/redwoodjs-icon.svg',
|
||||
},
|
||||
href: '/guides/with-redwoodjs',
|
||||
},
|
||||
{
|
||||
name: 'SolidJS',
|
||||
logo: {
|
||||
light: '/docs/img/libraries/solidjs-icon.svg',
|
||||
dark: '/docs/img/libraries/solidjs-icon.svg',
|
||||
},
|
||||
href: '/guides/with-solidjs',
|
||||
},
|
||||
{
|
||||
name: 'Svelte',
|
||||
logo: {
|
||||
light: '/docs/img/libraries/svelte-icon.svg',
|
||||
dark: '/docs/img/libraries/svelte-icon.svg',
|
||||
},
|
||||
href: '/guides/with-svelte',
|
||||
},
|
||||
{
|
||||
name: 'Vue',
|
||||
logo: {
|
||||
light: '/docs/img/libraries/vuejs-icon.svg',
|
||||
dark: '/docs/img/libraries/vuejs-icon.svg',
|
||||
},
|
||||
href: '/guides/with-vue-3',
|
||||
},
|
||||
]
|
||||
return (
|
||||
<div className="grid md:grid-cols-12 gap-4">
|
||||
{frameworks.map((x) => (
|
||||
<div key={x.name} className="col-span-3">
|
||||
<ButtonCard
|
||||
layout="horizontal"
|
||||
to={x.href}
|
||||
title={x.name}
|
||||
// [Joshen] Nice to have: theming
|
||||
icon={isDarkMode ? x.logo.dark : x.logo.light}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Frameworks
|
||||
+29
-27
@@ -1,10 +1,5 @@
|
||||
---
|
||||
id: examples
|
||||
title: Examples
|
||||
description: Useful Supabase Edge Functions Examples.
|
||||
---
|
||||
import ButtonCard from 'components/ButtonCard'
|
||||
|
||||
import ButtonCard from '@site/src/components/ButtonCard'
|
||||
const examples = [
|
||||
{
|
||||
name: 'With supabase-js',
|
||||
@@ -28,36 +23,43 @@ const examples = [
|
||||
},
|
||||
{
|
||||
name: 'Building a RESTful Service API',
|
||||
description: 'Learn how to use HTTP methods and paths to build a RESTful service for managing tasks.',
|
||||
description:
|
||||
'Learn how to use HTTP methods and paths to build a RESTful service for managing tasks.',
|
||||
href: 'https://github.com/supabase/supabase/blob/master/examples/edge-functions/supabase/functions/restful-tasks/index.ts',
|
||||
},
|
||||
{
|
||||
name: 'Working with Supabase Storage',
|
||||
description: 'An example on reading a file from Supbase Storage.',
|
||||
description: 'An example on reading a file from Supabase Storage.',
|
||||
href: 'https://github.com/supabase/supabase/blob/master/examples/edge-functions/supabase/functions/read-storage/index.ts',
|
||||
},
|
||||
{
|
||||
{
|
||||
name: 'OpenGraph Image Generation',
|
||||
description: 'Generate Open Graph images with Deno and Supabase Edge Functions, no framework needed.',
|
||||
description:
|
||||
'Generate Open Graph images with Deno and Supabase Edge Functions, no framework needed.',
|
||||
href: 'https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/opengraph',
|
||||
},
|
||||
|
||||
{
|
||||
name: 'OG Image Generation & Storage CDN Caching',
|
||||
description: 'Cache generated images with Supabase Storage CDN.',
|
||||
href: 'https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/og-image-with-storage-cdn',
|
||||
},
|
||||
{
|
||||
name: 'Get User Location',
|
||||
description: `Get user location data from user's IP address.`,
|
||||
href: 'https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/location',
|
||||
},
|
||||
]
|
||||
|
||||
You can find a list of useful [Edge Function Examples](https://github.com/supabase/supabase/tree/master/examples/edge-functions) in our GitHub repository.
|
||||
const FunctionsExamples = () => {
|
||||
return (
|
||||
<div className="grid md:grid-cols-12 gap-4">
|
||||
{examples.map((x) => (
|
||||
<div className="col-span-6">
|
||||
<ButtonCard to={x.href} title={x.name} description={x.description} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
<div class="container" style={{ padding: 0 }}>
|
||||
<div class="row is-multiline">
|
||||
{examples.map((x) => (
|
||||
<div class="col col--6">
|
||||
<ButtonCard
|
||||
class="card"
|
||||
to={x.href}
|
||||
title={x.name}
|
||||
description={x.description}
|
||||
style={{ height: '100%' }}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
export default FunctionsExamples
|
||||
@@ -0,0 +1,17 @@
|
||||
import React from 'react'
|
||||
|
||||
export default function GithubCard({ title, description, href, stars, handle }) {
|
||||
return (
|
||||
<a className="h-full" href={href}>
|
||||
<div className="card__body">
|
||||
<h4 className="uppercase my-2 font-semibold">{title}</h4>
|
||||
<span className="text-sm">{description}</span>
|
||||
</div>
|
||||
<hr className="my-2" />
|
||||
<div className="flex justify-between py-2 text-xs">
|
||||
<div>@{handle}</div>
|
||||
<div>{stars} ★</div>
|
||||
</div>
|
||||
</a>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
import { FC } from 'react'
|
||||
import { removeAnchor } from './CustomHTMLElements/CustomHTMLElements.utils'
|
||||
|
||||
const formatSlug = (slug: string) => {
|
||||
// [Joshen] We will still provide support for headers declared like this:
|
||||
// ## REST API {#rest-api-overview}
|
||||
// At least for now, this was a docusaurus thing.
|
||||
if (slug.includes('#')) return slug.split('#')[1]
|
||||
return slug
|
||||
}
|
||||
|
||||
const formatTOCHeader = (content: string) => {
|
||||
let begin = false
|
||||
const res = []
|
||||
for (const x of content) {
|
||||
if (x === '`') {
|
||||
if (!begin) {
|
||||
begin = true
|
||||
res.push(`<code class="text-xs border rounded bg-scale-400 border-scale-500">`)
|
||||
} else {
|
||||
begin = false
|
||||
res.push(`</code>`)
|
||||
}
|
||||
} else {
|
||||
res.push(x)
|
||||
}
|
||||
}
|
||||
return res.join('')
|
||||
}
|
||||
|
||||
interface TOCHeader {
|
||||
id: number
|
||||
level: number
|
||||
text: string
|
||||
link: string
|
||||
}
|
||||
|
||||
interface Props {
|
||||
list: TOCHeader[]
|
||||
}
|
||||
|
||||
const GuidesTableOfContents: FC<Props> = ({ list }) => {
|
||||
return (
|
||||
<ul className="toc-menu list-none pl-4 text-[0.8rem] grid gap-2 mt-12">
|
||||
{list.map((item, i) => (
|
||||
<li key={`${item.level}-${i}`} className={item.level === 3 ? 'ml-4' : ''}>
|
||||
<a
|
||||
href={`#${formatSlug(item.link)}`}
|
||||
className="text-scale-1000 hover:text-brand-900 transition-colors"
|
||||
dangerouslySetInnerHTML={{ __html: formatTOCHeader(removeAnchor(item.text)) }}
|
||||
/>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
// <ul className="toc-menu list-none pl-4 text-[0.8rem] grid gap-2 mt-12">
|
||||
// {(toc.json as TOCHeader[])
|
||||
// .filter((item) => item.lvl !== 1 && item.lvl <= 3)
|
||||
// .map((item: any, i: number) => {
|
||||
// return (
|
||||
// <li key={i} id={item.lvl} style={{ marginLeft: `${(item.lvl - 2) * 1}rem` }}>
|
||||
// <a
|
||||
// href={`#${formatSlug(item.slug)}`}
|
||||
// className="text-scale-1000 hover:text-brand-900 transition-colors"
|
||||
// dangerouslySetInnerHTML={{ __html: formatTOCHeader(removeAnchor(item.content)) }}
|
||||
// />
|
||||
// </li>
|
||||
// )
|
||||
// })}
|
||||
// </ul>
|
||||
)
|
||||
}
|
||||
|
||||
export default GuidesTableOfContents
|
||||
+27
-47
@@ -1,6 +1,7 @@
|
||||
import React, { useState } from 'react'
|
||||
import KJUR from 'jsrsasign'
|
||||
import CustomCodeBlock from './CustomCodeBlock'
|
||||
import CodeBlock from './CodeBlock/CodeBlock'
|
||||
import { Button } from 'ui'
|
||||
|
||||
const JWT_HEADER = { alg: 'HS256', typ: 'JWT' }
|
||||
const now = new Date()
|
||||
@@ -25,9 +26,7 @@ const serviceToken = `
|
||||
`.trim()
|
||||
|
||||
export default function JwtGenerator({}) {
|
||||
const secret = [...Array(40)]
|
||||
.map(() => Math.random().toString(36)[2])
|
||||
.join('')
|
||||
const secret = [...Array(40)].map(() => Math.random().toString(36)[2]).join('')
|
||||
|
||||
const [jwtSecret, setJwtSecret] = useState(secret)
|
||||
const [token, setToken] = useState(anonToken)
|
||||
@@ -45,72 +44,53 @@ export default function JwtGenerator({}) {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div style={styles.inputContainer}>
|
||||
<label>JWT Secret:</label>
|
||||
<div className="grid mb-8">
|
||||
<label for="secret">JWT Secret:</label>
|
||||
<input
|
||||
id="secret"
|
||||
className="border rounded bg-gray-200 w-full"
|
||||
type="text"
|
||||
style={styles.input}
|
||||
placeholder="JWT Secret (at least 32 characters)"
|
||||
value={jwtSecret}
|
||||
onChange={(e) => setJwtSecret(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div style={styles.inputContainer}>
|
||||
<label>Preconfigured Payload:</label>
|
||||
<select onChange={handleKeySelection} style={styles.input}>
|
||||
<div className="grid mb-8">
|
||||
<label for="service">Preconfigured Payload:</label>
|
||||
<select
|
||||
id="service"
|
||||
onChange={handleKeySelection}
|
||||
className="border rounded bg-gray-200 w-full"
|
||||
>
|
||||
<option value="anon">ANON_KEY</option>
|
||||
<option value="service">SERVICE_KEY</option>
|
||||
</select>
|
||||
</div>
|
||||
<div style={styles.inputContainer}>
|
||||
<label>Payload:</label>
|
||||
|
||||
<div className="grid mb-8">
|
||||
<label for="token">Payload:</label>
|
||||
<textarea
|
||||
id="token"
|
||||
type="text"
|
||||
style={styles.input}
|
||||
rows="5"
|
||||
placeholder="A valid JWT Token"
|
||||
value={token}
|
||||
onChange={(e) => setToken(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<button className="button button--primary" onClick={generate}>
|
||||
|
||||
<Button type="primary" onClick={generate}>
|
||||
Generate JWT
|
||||
</button>
|
||||
</Button>
|
||||
|
||||
{signedToken && (
|
||||
<div style={{ marginTop: 20 }}>
|
||||
<h4>Generated Token</h4>
|
||||
<CustomCodeBlock code={signedToken} />
|
||||
<div className="mt-8">
|
||||
<h4>Generated Token:</h4>
|
||||
<CodeBlock language="bash" className="relative">
|
||||
{signedToken}
|
||||
</CodeBlock>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = {
|
||||
inputContainer: {
|
||||
marginBottom: '15px',
|
||||
},
|
||||
input: {
|
||||
border: '1px solid var(--ifm-panel-border-color)',
|
||||
borderRadius: 4,
|
||||
backgroundColor: 'var(--custom-background-color-diff)',
|
||||
color: 'var(--ifm-font-color-base)',
|
||||
margin: 0,
|
||||
padding: '6px 8px',
|
||||
width: '100%',
|
||||
},
|
||||
card: {
|
||||
border: '1px solid var(--ifm-panel-border-color)',
|
||||
borderRadius: 5,
|
||||
padding: 8,
|
||||
},
|
||||
title: {
|
||||
margin: 0,
|
||||
fontSize: '0.9rem',
|
||||
border: '1px solid var(--ifm-panel-border-color)',
|
||||
},
|
||||
description: {
|
||||
fontSize: '0.8rem',
|
||||
margin: 0,
|
||||
},
|
||||
}
|
||||
@@ -9,7 +9,7 @@ export default function LinkCard({
|
||||
}: {
|
||||
title: string
|
||||
description: string
|
||||
icon: ReactElement
|
||||
icon: any
|
||||
link: string
|
||||
}) {
|
||||
return (
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { ReactElement } from 'react'
|
||||
|
||||
export default function LinkCardsWrapper({ children }: { children: ReactElement }) {
|
||||
export default function LinkCardsWrapper({ children }: { children: any }) {
|
||||
return <div className="flex w-full flex-col lg:flex-row lg:flex-wrap">{children}</div>
|
||||
}
|
||||
+14
-25
@@ -1,6 +1,4 @@
|
||||
import Tabs from '@theme/Tabs'
|
||||
import TabItem from '@theme/TabItem'
|
||||
import UserManagementSQLTemplate from './user_management_quickstart_sql_template.md'
|
||||
import UserManagementSQLTemplate from './user_management_quickstart_sql_template.mdx'
|
||||
|
||||
## Project set up
|
||||
|
||||
@@ -20,31 +18,27 @@ Now we are going to set up the database schema. We can use the "User Management
|
||||
or you can just copy/paste the SQL from below and run it yourself.
|
||||
|
||||
<Tabs
|
||||
groupId="language"
|
||||
defaultValue="dashboard"
|
||||
values={[
|
||||
{label: 'Dashboard', value: 'dashboard'},
|
||||
{label: 'SQL', value: 'sql'},
|
||||
]}>
|
||||
<TabItem value="dashboard">
|
||||
scrollable
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId="dashboard"
|
||||
>
|
||||
<TabPanel id="dashboard" label="Dashboard">
|
||||
|
||||
1. Go to the [SQL Editor](https://app.supabase.com/project/_/sql) page in the Dashboard.
|
||||
2. Click **User Management Starter**.
|
||||
3. Click **Run**.
|
||||
|
||||
<video width="99%" muted playsInline controls="true">
|
||||
<source
|
||||
src="/docs/videos/sql-user-management-starter.mp4"
|
||||
type="video/mp4"
|
||||
muted
|
||||
playsInline
|
||||
/>
|
||||
<source src="/docs/videos/sql-user-management-starter.mp4" type="video/mp4" muted playsInline />
|
||||
</video>
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="sql">
|
||||
</TabPanel>
|
||||
<TabPanel id="sql" label="SQL">
|
||||
|
||||
<UserManagementSQLTemplate />
|
||||
</TabItem>
|
||||
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
### Get the API Keys
|
||||
@@ -57,10 +51,5 @@ We just need to get the URL and `anon` key from the API settings.
|
||||
3. Find your API `URL`, `anon`, and `service_role` keys on this page.
|
||||
|
||||
<video width="99%" muted playsInline controls="true">
|
||||
<source
|
||||
src="/docs/videos/api/api-url-and-key.mp4"
|
||||
type="video/mp4"
|
||||
muted
|
||||
playsInline
|
||||
/>
|
||||
<source src="/docs/videos/api/api-url-and-key.mp4" type="video/mp4" muted playsInline />
|
||||
</video>
|
||||
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,169 @@
|
||||
import { render } from 'react-dom'
|
||||
import { IconCommand } from 'ui'
|
||||
import { createElement, FC, useEffect, useRef, Fragment } from 'react'
|
||||
import algoliasearch from 'algoliasearch/lite'
|
||||
import { autocomplete, getAlgoliaResults } from '@algolia/autocomplete-js'
|
||||
import { createLocalStorageRecentSearchesPlugin } from '@algolia/autocomplete-plugin-recent-searches'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
// [Joshen] We're currently using DocSearch from Algolia as it provides a nice
|
||||
// UI out of the box + some good preconfigured search settings (e.g hierarchy).
|
||||
// However, we're using our own Algolia account to store the records in the indexes
|
||||
// (rather than going through the DocSearch program from Algolia where they'll crawl
|
||||
// our site for us). Refer to scripts/build-search on how we're saving the records.
|
||||
|
||||
// Using Algolia's autocomplete library gives us full flexbility in terms of customizing
|
||||
// our search experience, but that will take time to figure out. Hence why for now we're just
|
||||
// using DocSearch with our own records.
|
||||
|
||||
// Potentially for search, we could
|
||||
// - Go ahead with the DocSearch program and let them crawl our site to generate the records
|
||||
// - But we need to ensure that our site is semantically correct first
|
||||
// - Use Algolia itself to flesh out our own search logic
|
||||
// - The basics are already set up to be honest, but will take time to make it great
|
||||
// - Go back to Typesense if we deem that Algolia is not helpful in the long run
|
||||
|
||||
const searchClient = algoliasearch(
|
||||
process.env.NEXT_PUBLIC_ALGOLIA_APP_ID,
|
||||
process.env.NEXT_PUBLIC_ALGOLIA_SEARCH_API_KEY
|
||||
)
|
||||
|
||||
// [Joshen] Not working properly, but lets not get stuck on this
|
||||
// Priority just to get a search working
|
||||
const recentSearchesPlugin = createLocalStorageRecentSearchesPlugin({
|
||||
key: 'docs-search',
|
||||
limit: 3,
|
||||
//@ts-ignore
|
||||
transformSource({ source }) {
|
||||
return {
|
||||
...source,
|
||||
templates: {
|
||||
...source.templates,
|
||||
header({ state }) {
|
||||
if (state.query) return null
|
||||
return (
|
||||
<Fragment>
|
||||
<span className="aa-SourceHeaderTitle">Your searches</span>
|
||||
<div className="aa-SourceHeaderLine" />
|
||||
</Fragment>
|
||||
)
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
interface Props {}
|
||||
|
||||
const AlgoliaSearch: FC<Props> = ({}) => {
|
||||
const searchRef = useRef(null)
|
||||
const router = useRouter()
|
||||
|
||||
useEffect(() => {
|
||||
if (!searchRef.current) {
|
||||
return undefined
|
||||
}
|
||||
const search = autocomplete({
|
||||
openOnFocus: true,
|
||||
container: searchRef.current,
|
||||
defaultActiveItemId: 0,
|
||||
detachedMediaQuery: '',
|
||||
// @ts-ignore
|
||||
renderer: { createElement, Fragment, render },
|
||||
placeholder: 'Search docs',
|
||||
plugins: [recentSearchesPlugin],
|
||||
renderNoResults({ state, render }, root) {
|
||||
render(
|
||||
<div className="text-scale-1100 py-2 text-sm px-4">
|
||||
No results found for {state.query}.
|
||||
</div>,
|
||||
root
|
||||
)
|
||||
},
|
||||
navigator: {
|
||||
navigate({ itemUrl }) {
|
||||
router.push(itemUrl)
|
||||
},
|
||||
},
|
||||
onSelect({ item, setQuery, setIsOpen, refresh }) {
|
||||
console.log('onSelect', item.url)
|
||||
},
|
||||
// @ts-ignore
|
||||
getSources({ query }) {
|
||||
return [
|
||||
{
|
||||
sourceId: 'pages',
|
||||
templates: {
|
||||
item({ item, components }) {
|
||||
return (
|
||||
<a
|
||||
href={item.url as string}
|
||||
className="aa-ItemLink truncate flex justify-between space-x-4"
|
||||
>
|
||||
<div className="aa-ItemContent w-full">
|
||||
<div className="aa-ItemTitle flex items-center space-x-1">
|
||||
{item.category && (
|
||||
<p
|
||||
className={`${
|
||||
['cli', 'api'].includes(item.category as string)
|
||||
? 'uppercase'
|
||||
: 'capitalize'
|
||||
}`}
|
||||
>
|
||||
<>
|
||||
{item.category}
|
||||
{item.version ? ` (${item.version})` : ''}:
|
||||
</>
|
||||
</p>
|
||||
)}
|
||||
<p>
|
||||
<components.Highlight hit={item} attribute="title" />
|
||||
</p>
|
||||
</div>
|
||||
<p className="aa-ItemContentSubtitle">{item.description as string}</p>
|
||||
</div>
|
||||
</a>
|
||||
)
|
||||
},
|
||||
},
|
||||
getItemUrl({ item }) {
|
||||
return item.url
|
||||
},
|
||||
getItems() {
|
||||
// if (!query) return []
|
||||
return getAlgoliaResults({
|
||||
searchClient,
|
||||
queries: [
|
||||
{
|
||||
indexName: 'dev_docs',
|
||||
query,
|
||||
},
|
||||
],
|
||||
})
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
})
|
||||
|
||||
return () => {
|
||||
search.destroy()
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="w-[200px] relative">
|
||||
<div ref={searchRef} />
|
||||
<div className="flex items-center space-x-1 absolute top-[7px] right-2">
|
||||
<div className="text-scale-1200 flex items-center justify-center h-6 w-6 rounded bg-scale-500">
|
||||
<IconCommand size={12} strokeWidth={1.5} />
|
||||
</div>
|
||||
<div className="text-xs text-scale-1200 flex items-center justify-center h-6 w-6 rounded bg-scale-500">
|
||||
K
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default AlgoliaSearch
|
||||
+32
-16
@@ -2,9 +2,10 @@ import Image from 'next/image'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useState, useEffect, FC } from 'react'
|
||||
import { IconMenu, IconSearch, Input, IconCommand, Button, IconMoon, IconSun, Listbox } from 'ui'
|
||||
import { IconMenu, IconMoon, IconSearch, IconSun, IconCommand, Listbox } from 'ui'
|
||||
import { useTheme } from '../Providers'
|
||||
import { REFERENCES } from './Navigation.constants'
|
||||
import { SearchButton } from '../DocSearch'
|
||||
|
||||
interface Props {
|
||||
currentPage: string
|
||||
@@ -13,6 +14,7 @@ interface Props {
|
||||
const NavBar: FC<Props> = ({ currentPage }) => {
|
||||
const { isDarkMode, toggleTheme } = useTheme()
|
||||
const [mounted, setMounted] = useState(false)
|
||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
|
||||
|
||||
const { asPath, push } = useRouter()
|
||||
const pathSegments = asPath.split('/')
|
||||
@@ -52,16 +54,26 @@ const NavBar: FC<Props> = ({ currentPage }) => {
|
||||
}
|
||||
}
|
||||
|
||||
// [Joshen] Kaizen: Use UI library's SidePanel for this
|
||||
const toggleMobileMenu = () => {
|
||||
setMobileMenuOpen(!mobileMenuOpen)
|
||||
const sidebar = document.querySelector('.sidebar-menu-container')
|
||||
const contentPane = document.querySelector('.main-content-pane')
|
||||
|
||||
sidebar.classList.toggle('hidden')
|
||||
contentPane.classList.toggle('hidden')
|
||||
}
|
||||
|
||||
return (
|
||||
<nav
|
||||
className={[
|
||||
'sticky top-0 z-10 flex items-center justify-between',
|
||||
'h-[60px] border-b bg-white p-4 backdrop-blur backdrop-filter',
|
||||
'h-[60px] border-b bg-white px-4 backdrop-blur backdrop-filter',
|
||||
'dark:border-scale-400 dark:bg-scale-200',
|
||||
].join(' ')}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<button className="mr-4 block stroke-2 lg:hidden">
|
||||
<button className="mr-4 block stroke-2 lg:hidden" onClick={toggleMobileMenu}>
|
||||
<IconMenu className="text-scale-1100" />
|
||||
</button>
|
||||
{mounted && (
|
||||
@@ -111,6 +123,7 @@ const NavBar: FC<Props> = ({ currentPage }) => {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex items-center space-x-4">
|
||||
<div className="hidden items-center md:flex">
|
||||
<ul className="flex items-center">
|
||||
@@ -180,19 +193,22 @@ const NavBar: FC<Props> = ({ currentPage }) => {
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<Input
|
||||
placeholder="Search"
|
||||
icon={<IconSearch />}
|
||||
type="search"
|
||||
actions={[
|
||||
<Button disabled key="icon-command" type="default" size="tiny">
|
||||
<IconCommand size="tiny" />
|
||||
</Button>,
|
||||
<Button disabled key="icon-letter" type="default" size="tiny">
|
||||
K
|
||||
</Button>,
|
||||
]}
|
||||
/>
|
||||
<SearchButton>
|
||||
<div className="flex items-center justify-between space-x-6 bg-scale-300 border border-scale-700 pl-3 pr-1.5 py-1.5 rounded">
|
||||
<div className="flex items-center space-x-2">
|
||||
<IconSearch className="text-scale-1100" size={18} strokeWidth={2} />
|
||||
<p className="text-scale-800 text-sm">Search</p>
|
||||
</div>
|
||||
<div className="flex items-center space-x-1">
|
||||
<div className="hidden text-scale-1200 md:flex items-center justify-center h-6 w-6 rounded bg-scale-500">
|
||||
<IconCommand size={12} strokeWidth={1.5} />
|
||||
</div>
|
||||
<div className="hidden text-xs text-scale-1200 md:flex items-center justify-center h-6 w-6 rounded bg-scale-500">
|
||||
K
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</SearchButton>
|
||||
</div>
|
||||
</nav>
|
||||
)
|
||||
+72
-36
@@ -1,3 +1,5 @@
|
||||
// [Terry] Also need to look at getPageType() in ./lib/helpers
|
||||
// to set a menu to a page
|
||||
import SupabaseJsV1Nav from 'data/nav/supabase-js/v1'
|
||||
import SupabaseJsV2Nav from 'data/nav/supabase-js/v2'
|
||||
import SupabaseDartV0Nav from 'data/nav/supabase-dart/v0'
|
||||
@@ -5,6 +7,7 @@ import SupabaseDartV1Nav from 'data/nav/supabase-dart/v1'
|
||||
import SupabaseCLINav from 'data/nav/supabase-cli'
|
||||
import SupabaseAPINav from 'data/nav/supabase-api'
|
||||
import AuthServerNav from 'data/nav/auth-server'
|
||||
import RealtimeServerNav from 'data/nav/realtime-server'
|
||||
import StorageServerNav from 'data/nav/storage-server'
|
||||
|
||||
import { NavMenu, References } from './Navigation.types'
|
||||
@@ -20,19 +23,19 @@ export const REFERENCES: References = {
|
||||
name: 'Flutter',
|
||||
library: 'supabase-dart',
|
||||
versions: ['v1', 'v0'],
|
||||
icon: '/docs/img/libraries/dart-icon.svg',
|
||||
icon: '/docs/img/libraries/flutter-icon.svg',
|
||||
},
|
||||
cli: {
|
||||
name: 'CLI',
|
||||
library: undefined,
|
||||
versions: [],
|
||||
icon: '/docs/img/libraries/cli-icon.svg',
|
||||
icon: '/docs/img/icons/cli-icon.svg',
|
||||
},
|
||||
api: {
|
||||
name: 'API',
|
||||
library: undefined,
|
||||
versions: [],
|
||||
icon: '/docs/img/libraries/api-icon.svg',
|
||||
icon: '/docs/img/icons/api-icon.svg',
|
||||
},
|
||||
}
|
||||
|
||||
@@ -42,7 +45,7 @@ export const menuItems: NavMenu = {
|
||||
label: 'Overview',
|
||||
items: [
|
||||
{ name: 'Introduction', url: '/', items: [] },
|
||||
{ name: 'Features', url: '/guides/features', items: [] },
|
||||
{ name: 'Features', url: '/features', items: [] },
|
||||
{ name: 'Architecture', url: '/architecture', items: [] },
|
||||
],
|
||||
},
|
||||
@@ -99,9 +102,13 @@ export const menuItems: NavMenu = {
|
||||
{ name: 'Login with Twitch', url: '/guides/auth/auth-twitch', items: [] },
|
||||
{ name: 'Login with Twitter', url: '/guides/auth/auth-twitter', items: [] },
|
||||
{ name: 'Login with WorkOS', url: '/guides/auth/auth-workos', items: [] },
|
||||
{ name: 'Phone Auth with Twilio', url: '/guides/auth/twilio', items: [] },
|
||||
{ name: 'Phone Auth with Vonage', url: '/guides/auth/vonage', items: [] },
|
||||
{ name: 'Phone Auth with MessageBird', url: '/guides/auth/messagebird', items: [] },
|
||||
{ name: 'Phone Auth with Twilio', url: '/guides/auth/auth-twilio', items: [] },
|
||||
{ name: 'Phone Auth with Vonage', url: '/guides/auth/auth-vonage', items: [] },
|
||||
{
|
||||
name: 'Phone Auth with MessageBird',
|
||||
url: '/guides/auth/auth-messagebird',
|
||||
items: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -122,37 +129,40 @@ export const menuItems: NavMenu = {
|
||||
{ name: 'Overview', url: '/guides/auth/auth-helpers', items: [] },
|
||||
{ name: 'Auth UI', url: '/guides/auth/auth-helpers/auth-ui', items: [] },
|
||||
{ name: 'Next.js', url: '/guides/auth/auth-helpers/nextjs', items: [] },
|
||||
{
|
||||
name: 'Next.js Server Components',
|
||||
url: '/guides/auth/auth-helpers/nextjs-server-components',
|
||||
items: [],
|
||||
},
|
||||
{ name: 'SvelteKit', url: '/guides/auth/auth-helpers/sveltekit', items: [] },
|
||||
{ name: 'Remix', url: '/guides/auth/auth-helpers/remix', items: [] },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Deep Dive',
|
||||
url: undefined,
|
||||
items: [
|
||||
{ name: 'Part One: JWTs', url: 'learn/auth-deep-dive/auth-deep-dive-jwts', items: [] },
|
||||
{
|
||||
name: 'Part Two: Row Level Security',
|
||||
url: 'learn/auth-deep-dive/auth-row-level-security',
|
||||
name: 'Part One: JWTs',
|
||||
url: '/learn/auth-deep-dive/auth-deep-dive-jwts',
|
||||
items: [],
|
||||
},
|
||||
{ name: 'Part Three: Policies', url: 'learn/auth-deep-dive/auth-policies', items: [] },
|
||||
{ name: 'Part Four: GoTrue', url: 'learn/auth-deep-dive/auth-gotrue', items: [] },
|
||||
{
|
||||
name: 'Part Fibe: Google OAuth',
|
||||
url: 'learn/auth-deep-dive/auth-google-oauth',
|
||||
name: 'Part Two: Row Level Security',
|
||||
url: '/learn/auth-deep-dive/auth-row-level-security',
|
||||
items: [],
|
||||
},
|
||||
{ name: 'Part Three: Policies', url: '/learn/auth-deep-dive/auth-policies', items: [] },
|
||||
{ name: 'Part Four: GoTrue', url: '/learn/auth-deep-dive/auth-gotrue', items: [] },
|
||||
{
|
||||
name: 'Part Five: Google OAuth',
|
||||
url: '/learn/auth-deep-dive/auth-google-oauth',
|
||||
items: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'APIs',
|
||||
items: [
|
||||
{ name: 'Overview', url: '/guides/api', items: [] },
|
||||
{ name: 'Generating Types', url: '/guides/api/generating-types', items: [] },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Database',
|
||||
items: [
|
||||
@@ -160,24 +170,39 @@ export const menuItems: NavMenu = {
|
||||
{ name: 'Database Connections', url: '/guides/database/connecting-to-postgres', items: [] },
|
||||
{ name: 'Tables and Data', url: '/guides/database/tables', items: [] },
|
||||
{ name: 'Database Functions', url: '/guides/database/functions', items: [] },
|
||||
{ name: 'Database Webhooks', url: '/guides/database/webhooks', items: [] },
|
||||
{ name: 'Full Text Search', url: '/guides/database/full-text-search', items: [] },
|
||||
{ name: 'Database Testing', url: '/guides/database/testing', items: [] },
|
||||
{
|
||||
name: 'Migrating Between Projects',
|
||||
url: '/guides/platform/migrating-and-upgrading-projects',
|
||||
items: [],
|
||||
name: 'Serverless APIs',
|
||||
url: undefined,
|
||||
items: [
|
||||
{ name: 'Overview', url: '/guides/api', items: [] },
|
||||
{ name: 'Generating Types', url: '/guides/api/generating-types', items: [] },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Extensions',
|
||||
url: undefined,
|
||||
items: [
|
||||
{ name: 'Overview', url: '/guides/database/extensions', items: [] },
|
||||
{ name: 'http: RESTful Client', url: '/guides/database/extensions/http', items: [] },
|
||||
{
|
||||
name: 'pg_cron: Job Scheduling',
|
||||
url: '/guides/database/extensions/pgcron',
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
name: 'pg_net: Async Networking',
|
||||
url: '/guides/database/extensions/pgnet',
|
||||
items: [],
|
||||
},
|
||||
{ name: 'pgTAP: Unit Testing', url: '/guides/database/extensions/pgtap', items: [] },
|
||||
{
|
||||
name: 'plv8: Javascript Language',
|
||||
url: '/guides/database/extensions/plv8',
|
||||
items: [],
|
||||
},
|
||||
{ name: 'http: RESTful Client', url: '/guides/database/extensions/http', items: [] },
|
||||
{ name: 'pgTAP: Unit Testing', url: '/guides/database/extensions/pgtap', items: [] },
|
||||
{
|
||||
name: 'uuid-ossp: Unique Identifiers',
|
||||
url: '/guides/database/extensions/uuid-ossp',
|
||||
@@ -212,6 +237,7 @@ export const menuItems: NavMenu = {
|
||||
{ name: 'Overview', url: '/guides/realtime', items: [] },
|
||||
{ name: 'Quickstart', url: '/guides/realtime/quickstart', items: [] },
|
||||
{ name: 'Postgres CDC', url: '/guides/realtime/postgres-cdc', items: [] },
|
||||
{ name: 'Rate Limits', url: '/guides/realtime/rate-limits', items: [] },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -225,11 +251,17 @@ export const menuItems: NavMenu = {
|
||||
label: 'Platform',
|
||||
items: [
|
||||
{ name: 'Overview', url: '/guides/hosting/platform', items: [] },
|
||||
{ name: 'Compute Add-ons', url: '/guides/platform/compute-add-ons', items: [] },
|
||||
{ name: 'Custom Domains', url: '/guides/platform/custom-domains', items: [] },
|
||||
{ name: 'Disk Space Usage', url: '/guides/platform/disk-usage', items: [] },
|
||||
{ name: 'Database Usage', url: '/guides/platform/database-usage', items: [] },
|
||||
{ name: 'Logging', url: '/guides/platform/logs', items: [] },
|
||||
{ name: 'Metrics', url: '/guides/platform/metrics', items: [] },
|
||||
{ name: 'Performance', url: '/guides/platform/performance', items: [] },
|
||||
{
|
||||
name: 'Migrating and upgrading',
|
||||
url: '/guides/platform/migrating-and-upgrading-projects',
|
||||
items: [],
|
||||
},
|
||||
{ name: 'Performance Tuning', url: '/guides/platform/performance', items: [] },
|
||||
{ name: 'Permissions', url: '/guides/platform/permissions', items: [] },
|
||||
{ name: 'Production Readiness', url: '/guides/platform/going-into-prod', items: [] },
|
||||
],
|
||||
@@ -247,7 +279,7 @@ export const menuItems: NavMenu = {
|
||||
{ name: 'Firebase Auth', url: '/guides/migrations/firebase-auth', items: [] },
|
||||
{ name: 'Firestore Data', url: '/guides/migrations/firestore-data', items: [] },
|
||||
{ name: 'Firebase Storage', url: '/guides/migrations/firebase-storage', items: [] },
|
||||
{ name: 'Herokuy', url: '/guides/migrations/heroku', items: [] },
|
||||
{ name: 'Heroku', url: '/guides/migrations/heroku', items: [] },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -258,12 +290,12 @@ export const menuItems: NavMenu = {
|
||||
name: 'Auth',
|
||||
url: undefined,
|
||||
items: [
|
||||
{ name: 'Auth0', url: '/guides/integration/auth0', items: [] },
|
||||
{ name: 'Authsignal', url: '/guides/integration/authsignal', items: [] },
|
||||
{ name: 'Clerk', url: '/guides/integration/clerk', items: [] },
|
||||
{ name: 'keyri', url: '/guides/integration/keyri', items: [] },
|
||||
{ name: 'Stytch', url: '/guides/integration/stytch', items: [] },
|
||||
{ name: 'SuperTokens', url: '/guides/integration/supertokens', items: [] },
|
||||
{ name: 'Auth0', url: '/guides/integrations/auth0', items: [] },
|
||||
{ name: 'Authsignal', url: '/guides/integrations/authsignal', items: [] },
|
||||
{ name: 'Clerk', url: '/guides/integrations/clerk', items: [] },
|
||||
{ name: 'keyri', url: '/guides/integrations/keyri', items: [] },
|
||||
{ name: 'Stytch', url: '/guides/integrations/stytch', items: [] },
|
||||
{ name: 'SuperTokens', url: '/guides/integrations/supertokens', items: [] },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -275,6 +307,7 @@ export const menuItems: NavMenu = {
|
||||
name: 'Developer Tools',
|
||||
url: undefined,
|
||||
items: [
|
||||
{ name: 'Estuary', url: '/guides/integrations/estuary', items: [] },
|
||||
{ name: 'pgMustard', url: '/guides/integrations/pgmustard', items: [] },
|
||||
{ name: 'Prisma', url: '/guides/integrations/prisma', items: [] },
|
||||
{ name: 'Sequin', url: '/guides/integrations/sequin', items: [] },
|
||||
@@ -292,6 +325,7 @@ export const menuItems: NavMenu = {
|
||||
{ name: 'Directus', url: '/guides/integrations/directus', items: [] },
|
||||
{ name: 'Draftbit', url: '/guides/integrations/draftbit', items: [] },
|
||||
{ name: 'Plasmic', url: '/guides/integrations/plasmic', items: [] },
|
||||
{ name: 'WeWeb', url: '/guides/integrations/weweb', items: [] },
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -302,7 +336,7 @@ export const menuItems: NavMenu = {
|
||||
label: 'Official',
|
||||
items: [
|
||||
{ name: 'Reference Documentation', url: '/reference', items: [] },
|
||||
{ name: 'Supabase Javascript Library', url: '/reference/javascript', items: [] },
|
||||
{ name: 'Supabase JavaScript Library', url: '/reference/javascript', items: [] },
|
||||
{ name: 'Supabase Flutter Library', url: '/reference/dart', items: [] },
|
||||
{ name: 'Supabase CLI', url: '/reference/cli', items: [] },
|
||||
{ name: 'Management API', url: '/reference/api', items: [] },
|
||||
@@ -312,6 +346,7 @@ export const menuItems: NavMenu = {
|
||||
label: 'Self-hosting',
|
||||
items: [
|
||||
{ name: 'Auth Server', url: '/reference/auth', items: [] },
|
||||
{ name: 'Realtime Server', url: '/reference/realtime', items: [] },
|
||||
{ name: 'Storage Server', url: '/reference/storage', items: [] },
|
||||
],
|
||||
},
|
||||
@@ -323,5 +358,6 @@ export const menuItems: NavMenu = {
|
||||
'reference/cli': SupabaseCLINav,
|
||||
'reference/api': SupabaseAPINav,
|
||||
'reference/auth': AuthServerNav,
|
||||
'reference/realtime': RealtimeServerNav,
|
||||
'reference/storage': StorageServerNav,
|
||||
}
|
||||
File renamed without changes.
+8
-10
@@ -42,8 +42,8 @@ const SideBar = ({ menuItems = [] }: { menuItems: any }) => {
|
||||
|
||||
return (
|
||||
<div
|
||||
className="dark:bg-scale-200 dark:border-scale-400 sidebar-width sticky top-0
|
||||
h-screen overflow-y-scroll border-r py-8 px-6 sidebar-menu-container"
|
||||
className="dark:bg-scale-200 dark:border-scale-400 sidebar-width sticky top-16
|
||||
h-screen overflow-y-scroll border-r py-8 px-6 sidebar-menu-container hidden lg:block"
|
||||
>
|
||||
{isInReferencePages && (
|
||||
<>
|
||||
@@ -73,9 +73,8 @@ const SideBar = ({ menuItems = [] }: { menuItems: any }) => {
|
||||
)}
|
||||
{menuItems.length === 1 ? (
|
||||
<div className="my-2">
|
||||
<h4 className="text-scale-1200 pt-2 pb-3">{menuItems[0].label}</h4>
|
||||
{menuItems[0].items.map((item) => (
|
||||
<Link href={item.url}>
|
||||
<Link key={item.name} href={item.url}>
|
||||
<a>
|
||||
<div
|
||||
key={item.name}
|
||||
@@ -83,7 +82,7 @@ const SideBar = ({ menuItems = [] }: { menuItems: any }) => {
|
||||
'py-1.5 px-5 rounded text-sm transition',
|
||||
`${
|
||||
item.url === asPath
|
||||
? 'bg-scale-400 text-brand-900'
|
||||
? 'bg-scale-200 text-brand-900'
|
||||
: 'text-scale-1100 hover:text-scale-1200'
|
||||
}`,
|
||||
].join(' ')}
|
||||
@@ -117,15 +116,14 @@ const SideBar = ({ menuItems = [] }: { menuItems: any }) => {
|
||||
{group.items.map((section: NavMenuSection) => {
|
||||
if (section.items.length === 0) {
|
||||
return (
|
||||
<Link href={section.url}>
|
||||
<Link href={section.url} key={section.name}>
|
||||
<a>
|
||||
<div
|
||||
key={section.name}
|
||||
className={[
|
||||
'py-1.5 px-5 rounded text-sm transition',
|
||||
`${
|
||||
section.url === asPath
|
||||
? 'bg-scale-400 text-brand-900'
|
||||
? 'bg-scale-200 text-brand-900'
|
||||
: 'text-scale-1100 hover:text-scale-1200'
|
||||
}`,
|
||||
].join(' ')}
|
||||
@@ -157,7 +155,7 @@ const SideBar = ({ menuItems = [] }: { menuItems: any }) => {
|
||||
</Accordion.Trigger>
|
||||
<Accordion.Content className="my-2 data-open:animate-slide-down data-closed:animate-slide-up">
|
||||
{section.items.map((item: NavMenuSection) => (
|
||||
<Link href={item.url}>
|
||||
<Link key={item.name} href={item.url}>
|
||||
<a>
|
||||
<div
|
||||
key={item.name}
|
||||
@@ -165,7 +163,7 @@ const SideBar = ({ menuItems = [] }: { menuItems: any }) => {
|
||||
'py-1.5 ml-4 px-5 rounded text-sm transition',
|
||||
`${
|
||||
item.url === asPath
|
||||
? 'bg-scale-400 text-brand-900'
|
||||
? 'bg-scale-200 text-brand-900'
|
||||
: 'text-scale-1100 hover:text-scale-1200'
|
||||
}`,
|
||||
].join(' ')}
|
||||
@@ -1,7 +1,7 @@
|
||||
import Link from 'next/link'
|
||||
import { IconArrowLeft, IconArrowRight } from 'ui'
|
||||
|
||||
const pagination = ({ currentPage, totalCount }: { currentPage: number; totalCount: number }) => {
|
||||
const Pagination = ({ currentPage, totalCount }: { currentPage: number; totalCount: number }) => {
|
||||
// TODO: not sure if this is the most efficient way to do this. may need to refactor.
|
||||
const totalArray = Array.from({ length: totalCount }, (_, i: number) => i + 1)
|
||||
const pages = totalArray.filter((page: number) => {
|
||||
@@ -50,4 +50,4 @@ const pagination = ({ currentPage, totalCount }: { currentPage: number; totalCou
|
||||
)
|
||||
}
|
||||
|
||||
export default pagination
|
||||
export default Pagination
|
||||
File renamed without changes.
@@ -1,5 +1,6 @@
|
||||
import Image from 'next/image'
|
||||
import React from 'react'
|
||||
import sponsors from '@site/src/data/sponsors.json'
|
||||
import sponsors from '../data/sponsors.json'
|
||||
|
||||
export default function Sponsors() {
|
||||
const tiers = [
|
||||
@@ -41,19 +42,22 @@ export default function Sponsors() {
|
||||
(t, index) =>
|
||||
!!t.transactions.length && (
|
||||
<div key={index}>
|
||||
<h4 className="">{t.heading}</h4>
|
||||
<div className="row is-multiline" style={{ paddingLeft: 15 }}>
|
||||
<h4 className="font-bold">{t.heading}</h4>
|
||||
<div className="grid sm:grid-cols-2 lg:grid-cols-3 gap-6 pl-4">
|
||||
{t.transactions.map((x, index) => (
|
||||
<div className="col col--4" key={index}>
|
||||
<div className="" key={index}>
|
||||
<a
|
||||
className="avatar"
|
||||
className="flex items-center gap-4 shadow-none shrink-0"
|
||||
href={`https://github.com/${x.sponsor}`}
|
||||
>
|
||||
<img
|
||||
className="avatar__photo avatar__photo--sm"
|
||||
<Image
|
||||
alt="Sponsor"
|
||||
className="mt-4 mb-4 rounded-full w-12 h-12"
|
||||
width={45}
|
||||
height={45}
|
||||
src={`https://github.com/${x.sponsor}.png`}
|
||||
/>
|
||||
<div className="avatar__intro">
|
||||
<div className="flex items-center flex-col justify-center text-center">
|
||||
<h5 className="avatar__name">{x.sponsor}</h5>
|
||||
</div>
|
||||
</a>
|
||||
@@ -0,0 +1,70 @@
|
||||
// [Terry]
|
||||
// Delete this after we've implemented GuidesTableofContents and moved all guides
|
||||
// and rename GuidesTableofContents to TableOfContents
|
||||
|
||||
import { FC } from 'react'
|
||||
import { getAnchor, removeAnchor } from './CustomHTMLElements/CustomHTMLElements.utils'
|
||||
|
||||
interface TOCHeader {
|
||||
id: number
|
||||
lvl: number
|
||||
seen: number
|
||||
content: string
|
||||
slug: string
|
||||
}
|
||||
|
||||
interface Props {
|
||||
toc: any
|
||||
}
|
||||
|
||||
const formatSlug = (slug: string) => {
|
||||
// [Joshen] We will still provide support for headers declared like this:
|
||||
// ## REST API {#rest-api-overview}
|
||||
// At least for now, this was a docusaurus thing.
|
||||
if (slug.includes('#')) return slug.split('-#')[1]
|
||||
return slug
|
||||
}
|
||||
|
||||
const formatTOCHeader = (content: string) => {
|
||||
let begin = false
|
||||
const res = []
|
||||
for (const x of content) {
|
||||
if (x === '`') {
|
||||
if (!begin) {
|
||||
begin = true
|
||||
res.push(`<code class="text-xs border rounded bg-scale-400 border-scale-500">`)
|
||||
} else {
|
||||
begin = false
|
||||
res.push(`</code>`)
|
||||
}
|
||||
} else {
|
||||
res.push(x)
|
||||
}
|
||||
}
|
||||
return res.join('')
|
||||
}
|
||||
|
||||
const TableOfContents: FC<Props> = ({ toc }) => {
|
||||
// [Joshen] markdown-toc doesn't seem to read maxdepth from the options passed in
|
||||
// Our first level headers will be H2s (H1 is ignored), and we only show up to H3
|
||||
|
||||
return (
|
||||
<ul className="toc-menu list-none pl-4 text-[0.8rem] grid gap-2 mt-12">
|
||||
{(toc.json as TOCHeader[])
|
||||
.filter((item) => item.lvl !== 1 && item.lvl <= 3)
|
||||
.map((item: any, i: number) => {
|
||||
return (
|
||||
<li key={i} id={item.lvl} style={{ marginLeft: `${(item.lvl - 2) * 1}rem` }}>
|
||||
<a
|
||||
href={`#${formatSlug(item.slug)}`}
|
||||
className="text-scale-1000 hover:text-brand-900 transition-colors"
|
||||
dangerouslySetInnerHTML={{ __html: formatTOCHeader(removeAnchor(item.content)) }}
|
||||
/>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
|
||||
export default TableOfContents
|
||||
@@ -0,0 +1,62 @@
|
||||
import { Button, Tabs, Alert } from 'ui'
|
||||
|
||||
// Common components
|
||||
import Admonition from './Admonition'
|
||||
import ButtonCard from './ButtonCard'
|
||||
import CodeBlock from './CodeBlock/CodeBlock'
|
||||
import { parseNumericRange } from './CodeBlock/CodeBlock.utils'
|
||||
import JwtGenerator from './JwtGenerator'
|
||||
|
||||
// Page specific components
|
||||
import Frameworks from './Frameworks'
|
||||
import AuthProviders from './AuthProviders'
|
||||
import FunctionsExamples from './FunctionsExamples'
|
||||
import Extensions from './Extensions'
|
||||
|
||||
// Other components
|
||||
import { Heading } from './CustomHTMLElements'
|
||||
import QuickstartIntro from './MDX/quickstart_intro.mdx'
|
||||
import ProjectSetup from './MDX/project_setup.mdx'
|
||||
import { Mermaid } from 'mdx-mermaid/lib/Mermaid'
|
||||
import InlineCodeTag from './CustomHTMLElements/InlineCode'
|
||||
|
||||
const components = {
|
||||
Admonition,
|
||||
Button,
|
||||
ButtonCard,
|
||||
CodeBlock,
|
||||
Frameworks,
|
||||
AuthProviders,
|
||||
FunctionsExamples,
|
||||
JwtGenerator,
|
||||
QuickstartIntro,
|
||||
ProjectSetup,
|
||||
Mermaid,
|
||||
Extensions,
|
||||
Alert: (props: any) => (
|
||||
<Alert {...props} className="not-prose">
|
||||
{props.children}
|
||||
</Alert>
|
||||
),
|
||||
Tabs,
|
||||
TabPanel: (props: any) => <Tabs.Panel {...props}>{props.children}</Tabs.Panel>,
|
||||
|
||||
h2: (props: any) => (
|
||||
<Heading tag="h2" {...props}>
|
||||
{props.children}
|
||||
</Heading>
|
||||
),
|
||||
h3: (props: any) => (
|
||||
<Heading tag="h3" {...props}>
|
||||
{props.children}
|
||||
</Heading>
|
||||
),
|
||||
code: (props: any) => {
|
||||
const linesToHighlight = parseNumericRange(props.lines ?? '')
|
||||
return <CodeBlock {...props} linesToHighlight={linesToHighlight} />
|
||||
},
|
||||
mono: (props: any) => <code className="text-sm">{props.children}</code>,
|
||||
inlineCode: (props: any) => <InlineCodeTag>{props.children}</InlineCodeTag>,
|
||||
}
|
||||
|
||||
export default components
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,150 @@
|
||||
[
|
||||
{
|
||||
"title": "Product",
|
||||
"links": [
|
||||
{
|
||||
"text": "Database",
|
||||
"url": "/database"
|
||||
},
|
||||
{
|
||||
"text": "Auth",
|
||||
"url": "/auth"
|
||||
},
|
||||
{
|
||||
"text": "Functions",
|
||||
"url": "/edge-functions"
|
||||
},
|
||||
{
|
||||
"text": "Realtime",
|
||||
"url": "/realtime"
|
||||
},
|
||||
{
|
||||
"text": "Storage",
|
||||
"url": "/storage"
|
||||
},
|
||||
{
|
||||
"text": "Pricing",
|
||||
"url": "/pricing"
|
||||
},
|
||||
{
|
||||
"text": "Beta",
|
||||
"url": "/beta"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Resources",
|
||||
"links": [
|
||||
{
|
||||
"text": "Support",
|
||||
"url": "/support"
|
||||
},
|
||||
{
|
||||
"text": "System Status",
|
||||
"url": "https://status.supabase.com/"
|
||||
},
|
||||
{
|
||||
"text": "Integrations",
|
||||
"url": "/partners/integrations"
|
||||
},
|
||||
{
|
||||
"text": "Experts",
|
||||
"url": "/partners/experts"
|
||||
},
|
||||
{
|
||||
"text": "Brand Assets / Logos",
|
||||
"url": "/brand-assets"
|
||||
},
|
||||
{
|
||||
"text": "DPA",
|
||||
"url": "/legal/dpa"
|
||||
},
|
||||
{
|
||||
"text": "SOC2",
|
||||
"url": "/legal/soc2"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Developers",
|
||||
"links": [
|
||||
{
|
||||
"text": "Documentation",
|
||||
"url": "/docs"
|
||||
},
|
||||
{
|
||||
"text": "API Reference",
|
||||
"url": "/docs/reference"
|
||||
},
|
||||
{
|
||||
"text": "Changelog",
|
||||
"url": "/changelog"
|
||||
},
|
||||
{
|
||||
"text": "Contributing",
|
||||
"url": "/docs/handbook/contributing"
|
||||
},
|
||||
{
|
||||
"text": "Open Source",
|
||||
"url": "/docs/oss"
|
||||
},
|
||||
{
|
||||
"text": "SupaSquad",
|
||||
"url": "/docs/handbook/supasquad"
|
||||
},
|
||||
{
|
||||
"text": "DevTo",
|
||||
"url": "https://dev.to/supabase"
|
||||
},
|
||||
{
|
||||
"text": "RSS",
|
||||
"url": "/rss.xml"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Company",
|
||||
"links": [
|
||||
{
|
||||
"text": "Blog",
|
||||
"url": "/blog"
|
||||
},
|
||||
{
|
||||
"text": "Careers",
|
||||
"url": "https://about.supabase.com/careers"
|
||||
},
|
||||
{
|
||||
"text": "Company",
|
||||
"url": "/company"
|
||||
},
|
||||
{
|
||||
"text": "Terms of Service",
|
||||
"url": "/docs/company/terms"
|
||||
},
|
||||
{
|
||||
"text": "Privacy Policy",
|
||||
"url": "/docs/company/privacy"
|
||||
},
|
||||
{
|
||||
"text": "Acceptable Use Policy",
|
||||
"url": "/docs/company/aup"
|
||||
},
|
||||
{
|
||||
"text": "Service Level Agreement",
|
||||
"url": "/docs/company/sla"
|
||||
},
|
||||
{
|
||||
"text": "Humans.txt",
|
||||
"url": "/humans.txt"
|
||||
},
|
||||
{
|
||||
"text": "Lawyers.txt",
|
||||
"url": "/lawyers.txt"
|
||||
},
|
||||
{
|
||||
"text": "Security.txt",
|
||||
"url": "/.well-known/security.txt"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,12 @@
|
||||
const Nav = [
|
||||
{
|
||||
label: 'Realtime',
|
||||
items: [
|
||||
{ name: 'Realtime Server', url: '/reference/realtime', items: [] },
|
||||
{ name: 'Configuration', url: '/reference/realtime/config', items: [] },
|
||||
{ name: 'Release Notes', url: '/reference/realtime/release-notes', items: [] },
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
export default Nav
|
||||
File renamed without changes.
@@ -2,7 +2,7 @@ const Nav = [
|
||||
{
|
||||
label: 'API',
|
||||
items: [
|
||||
{ name: 'Supabase API', url: '/reference/api', items: [] },
|
||||
{ name: 'Management API', url: '/reference/api', items: [] },
|
||||
{ name: 'Usage', url: '/reference/api/usage', items: [] },
|
||||
{ name: 'Release Notes', url: '/reference/api/release-notes', items: [] },
|
||||
],
|
||||
File renamed without changes.
File renamed without changes.
+6
-1
@@ -24,7 +24,7 @@ const Nav = [
|
||||
{ name: 'currentSession', url: '/reference/dart/auth-currentsession', items: [] },
|
||||
{ name: 'currentUser', url: '/reference/dart/auth-currentuser', items: [] },
|
||||
{ name: 'updateUser()', url: '/reference/dart/auth-updateuser', items: [] },
|
||||
{ name: 'setSession()', url: '/reference/dart/auth-setSession', items: [] },
|
||||
{ name: 'onAuthStateChange()', url: '/reference/dart/auth-onauthstatechange', items: [] },
|
||||
{
|
||||
name: 'resetPasswordForEmail()',
|
||||
url: '/reference/dart/auth-resetpasswordforemail',
|
||||
@@ -118,6 +118,11 @@ const Nav = [
|
||||
url: '/reference/dart/storage-from-createsignedurl',
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
name: 'from.createSignedUrls()',
|
||||
url: '/reference/dart/storage-from-createsignedurls',
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
name: 'from.getPublicUrl()',
|
||||
url: '/reference/dart/storage-from-getpublicurl',
|
||||
@@ -2,7 +2,7 @@ const Nav = [
|
||||
{
|
||||
label: 'Getting Started',
|
||||
items: [
|
||||
{ name: 'Supabase Javascript Library', url: '/reference/javascript/v1', items: [] },
|
||||
{ name: 'Supabase JavaScript Library', url: '/reference/javascript/v1', items: [] },
|
||||
{ name: 'Installing', url: '/reference/javascript/v1/installing', items: [] },
|
||||
{ name: 'Initializing', url: '/reference/javascript/v1/initializing', items: [] },
|
||||
{ name: 'Generating Types', url: '/reference/javascript/v1/generating-types', items: [] },
|
||||
@@ -2,7 +2,7 @@ const Nav = [
|
||||
{
|
||||
label: 'Getting Started',
|
||||
items: [
|
||||
{ name: 'Supabase Javascript Library', url: '/reference/javascript', items: [] },
|
||||
{ name: 'Supabase JavaScript Library', url: '/reference/javascript', items: [] },
|
||||
{ name: 'Installing', url: '/reference/javascript/installing', items: [] },
|
||||
{ name: 'Initializing', url: '/reference/javascript/initializing', items: [] },
|
||||
{ name: 'Typescript Support', url: '/reference/javascript/typescript-support', items: [] },
|
||||
@@ -28,9 +28,15 @@ const Nav = [
|
||||
{ name: 'signOut()', url: '/reference/javascript/auth-signout', items: [] },
|
||||
{ name: 'verifyOtp()', url: '/reference/javascript/auth-verifyotp', items: [] },
|
||||
{ name: 'getSession()', url: '/reference/javascript/auth-getsession', items: [] },
|
||||
{ name: 'refreshSession()', url: '/reference/javascript/auth-refreshsession', items: [] },
|
||||
{ name: 'getUser()', url: '/reference/javascript/auth-getuser', items: [] },
|
||||
{ name: 'updateUser()', url: '/reference/javascript/auth-updateuser', items: [] },
|
||||
{ name: 'setSession()', url: '/reference/javascript/auth-setSession', items: [] },
|
||||
{ name: 'setSession()', url: '/reference/javascript/auth-setsession', items: [] },
|
||||
{
|
||||
name: 'onAuthStateChange()',
|
||||
url: '/reference/javascript/auth-onauthstatechange',
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
name: 'resetPasswordForEmail()',
|
||||
url: '/reference/javascript/auth-resetpasswordforemail',
|
||||
+2
@@ -21,6 +21,8 @@ const nonGeneratedReferencePages = [
|
||||
'docs/reference/auth/release-notes',
|
||||
'docs/reference/storage',
|
||||
'docs/reference/storage/release-notes',
|
||||
'docs/reference/realtime',
|
||||
'docs/reference/realtime/release-notes',
|
||||
]
|
||||
|
||||
export default nonGeneratedReferencePages
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -1,11 +1,11 @@
|
||||
---
|
||||
slug: /
|
||||
sidebar_position: 1
|
||||
id: management-api
|
||||
title: Management API
|
||||
sidebar_label: Management API
|
||||
---
|
||||
|
||||
# Management API
|
||||
|
||||
The Management API allows you to manage your projects programmatically.
|
||||
|
||||
## Status
|
||||
File renamed without changes.
+2
-3
@@ -1,10 +1,9 @@
|
||||
---
|
||||
id: release-notes
|
||||
title: Release Notes
|
||||
---
|
||||
|
||||
# Release Notes
|
||||
|
||||
## v1.0.0 {#1.0.0}
|
||||
## v1.0.0 [#1.0.0]
|
||||
|
||||
Adds the following routes:
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
---
|
||||
slug: /
|
||||
sidebar_position: 1
|
||||
sidebar_label: Auth Server
|
||||
id: auth-server
|
||||
title: Supabase Auth Server
|
||||
sidebar_label: Supabase Auth Server
|
||||
---
|
||||
|
||||
# Supabase Auth Server
|
||||
|
||||
The Supabase Auth Server (GoTrue) is a JSON Web Token (JWT)-based API for managing users and issuing access tokens.
|
||||
|
||||
GoTrue is an open-source API written in Golang, that acts as a self-standing API service for handling user registration and authentication for JAM projects. It's based on OAuth2 and JWT and handles user signup, authentication, and custom user data.
|
||||
@@ -19,4 +19,4 @@ GoTrue is an open-source API written in Golang, that acts as a self-standing API
|
||||
|
||||
- [Source Code](https://github.com/supabase/gotrue)
|
||||
- [Known bugs and issues](https://github.com/supabase/gotrue/issues)
|
||||
- [Auth Guides](https://supabase.com/docs/guides/auth)
|
||||
- [Auth Guides](/docs/guides/auth)
|
||||
File renamed without changes.
+1
-2
@@ -1,7 +1,6 @@
|
||||
---
|
||||
id: release-notes
|
||||
title: Release Notes
|
||||
---
|
||||
|
||||
# Release Notes
|
||||
|
||||
All release notes can be found in the [GitHub Releases](https://github.com/supabase/gotrue/releases) page.
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
id: intro
|
||||
slug: /
|
||||
sidebar_position: 1
|
||||
sidebar_label: Supabase CLI
|
||||
title: Supabase CLI
|
||||
hide_table_of_contents: true
|
||||
---
|
||||
|
||||
The Supabase CLI provides tools to develop your project locally and deploy to the Supabase Platform.
|
||||
The CLI is still under development, but it contains all the functionality for working with your Supabase projects and the Supabase Platform.
|
||||
|
||||
- Run Supabase locally: [`supabase start`](/docs/reference/cli/usage#supabase-start)
|
||||
- Manage database migrations: [`supabase migration`](/docs/reference/cli/usage#supabase-migration)
|
||||
- CI/CD for releasing to production: [`supabase db push`](/docs/reference/cli/usage#supabase-db-push)
|
||||
- Manage your Supabase projects: [`supabase projects`](/docs/reference/cli/usage#supabase-projects)
|
||||
- Generate types directly from your database schema: [`supabase gen types`](/docs/reference/cli/usage#supabase-gen)
|
||||
- A [community-supported GitHub Action](https://github.com/lyqht/generate-supabase-db-types-github-action) to generate TypeScript types
|
||||
- Shell autocomplete: [`supabase completion`](/docs/reference/cli/usage#supabase-completion)
|
||||
- A [community-supported Fig autocomplete spec](https://fig.io/manual/supabase) for macOS terminal
|
||||
|
||||
## Additional Links
|
||||
|
||||
- [Install the Supabase CLI](/docs/guides/cli)
|
||||
- [Source code](https://github.com/supabase/cli)
|
||||
- [Known bugs and issues](https://github.com/supabase/cli/issues)
|
||||
- [Supabase CLI v1 and Management API Beta](https://supabase.com/blog/supabase-cli-v1-and-admin-api-beta)
|
||||
- [The CLI team announcing CLI V1 and Management API Beta - Video](https://www.youtube.com/watch?v=OpPOaJI_Z28)
|
||||
File renamed without changes.
+1
-2
@@ -1,7 +1,6 @@
|
||||
---
|
||||
id: release-notes
|
||||
title: Release Notes
|
||||
---
|
||||
|
||||
# Release Notes
|
||||
|
||||
All release notes can be found in the [GitHub Releases page](https://github.com/supabase/cli/releases).
|
||||
@@ -5,8 +5,6 @@ title: Supabase Flutter Library
|
||||
sidebar_label: Supabase Flutter Library
|
||||
---
|
||||
|
||||
# Supabase Flutter Library
|
||||
|
||||
This reference documents every object and method available in Supabase's isomorphic Flutter library, [`supabase-flutter`](https://pub.dev/packages/supabase_flutter).
|
||||
|
||||
You can use the `supabase-flutter` library to:
|
||||
File renamed without changes.
+28
-2
@@ -13,7 +13,7 @@ For `supabase-flutter`, you will be using the static `initialize()` method on `S
|
||||
|
||||
### Flutter `initialize()`
|
||||
|
||||
```dart title="main.dart"
|
||||
```dart title=main.dart
|
||||
Future<void> main() async {
|
||||
await Supabase.initialize(url: 'https://xyzcompany.supabase.co', anonKey: 'public-anon-key');
|
||||
runApp(MyApp());
|
||||
@@ -28,6 +28,33 @@ Once you initialize Supabase in your `main()` method, you can access the `Supaba
|
||||
final supabase = Supabase.instance.client;
|
||||
```
|
||||
|
||||
### Call `initialize()` with custom headers
|
||||
|
||||
You can pass `headers` to initialize your Supabase client with customer headers.
|
||||
Here is an example of passing a custom auth header to Supabase client.
|
||||
```dart title=main.dart
|
||||
Future<void> main() async {
|
||||
await Supabase.initialize(
|
||||
url: 'https://xyzcompany.supabase.co',
|
||||
anonKey: 'public-anon-key',
|
||||
headers: {
|
||||
'Authorization': 'Bearer $accessToken',
|
||||
},
|
||||
);
|
||||
runApp(const MyApp());
|
||||
}
|
||||
```
|
||||
|
||||
### Call `initialize()`multiple times
|
||||
|
||||
You can initialize Supabase multiple times in your app. When doing so, call `dispose()` each time before you initialize again.
|
||||
|
||||
```dart
|
||||
Supabase.instance.dispose();
|
||||
|
||||
await Supabase.initialize(url: 'https://xyzcompany.supabase.co', anonKey: 'public-anon-key');
|
||||
```
|
||||
|
||||
## Other Dart Projects
|
||||
|
||||
You can initialize a new Supabase client using the `SupabaseClient()` method.
|
||||
@@ -40,4 +67,3 @@ and is the easiest way to interact with everything we offer within the Supabase
|
||||
```dart
|
||||
final supabase = SupabaseClient('https://xyzcompany.supabase.co', 'public-anon-key');
|
||||
```
|
||||
|
||||
File renamed without changes.
+161
-195
@@ -22,26 +22,24 @@ supabase_flutter: ^1.0.0
|
||||
The way supabase-flutter throws error has changed in v1. In v0, errors were returned as a response. In v1, errors are thrown as exceptions. This makes it more intuitive as a Flutter developer to handle errors.
|
||||
|
||||
<Tabs
|
||||
groupId="version"
|
||||
values={[
|
||||
{label: 'Before', value: '0.x'},
|
||||
{label: 'After', value: '1.x'},
|
||||
]}>
|
||||
|
||||
<TabItem value="0.x">
|
||||
scrollable
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId="0.x"
|
||||
>
|
||||
<TabPanel id="0.x" label="Before">
|
||||
|
||||
```dart
|
||||
final res = await supabase.from('my_table').select().execute();
|
||||
final error = res.error;
|
||||
if(error != null) {
|
||||
if (error != null) {
|
||||
// handle error
|
||||
}
|
||||
final data = res.data;
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
<TabItem value="1.x">
|
||||
</TabPanel>
|
||||
<TabPanel id="1.0x" label="After">
|
||||
|
||||
```dart
|
||||
try {
|
||||
@@ -51,7 +49,7 @@ try {
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
## Auth classes / methods
|
||||
@@ -61,13 +59,12 @@ try {
|
||||
In v0, `SupabaseAuthState` and `SupabaseAuthRequiredState` were required to handle automatic token refresh and to listen to auth state change. In v1, `SupabaseAuthState` and `SupabaseAuthRequiredState` are deprecated, and token refresh will happen automatically just by initializing Supabase. [`onAuthStateChange`](/docs/reference/dart/upgrade-guide#listening-to-auth-state-change) can be used to action on auth state change.
|
||||
|
||||
<Tabs
|
||||
groupId="version"
|
||||
values={[
|
||||
{label: 'Before', value: '0.x'},
|
||||
{label: 'After', value: '1.x'},
|
||||
]}>
|
||||
|
||||
<TabItem value="0.x">
|
||||
scrollable
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId="0.x"
|
||||
>
|
||||
<TabPanel id="0.x" label="Before">
|
||||
|
||||
```dart
|
||||
await Supabase.initialize(
|
||||
@@ -87,9 +84,8 @@ class AuthRequiredState<T extends StatefulWidget> extends SupabaseAuthState<T> {
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
<TabItem value="1.x">
|
||||
</TabPanel>
|
||||
<TabPanel id="1.0x" label="After">
|
||||
|
||||
```dart
|
||||
await Supabase.initialize(
|
||||
@@ -98,7 +94,7 @@ await Supabase.initialize(
|
||||
);
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
### Listening to auth state change
|
||||
@@ -106,13 +102,12 @@ await Supabase.initialize(
|
||||
`onAuthStateChange` now returns a `Stream`.
|
||||
|
||||
<Tabs
|
||||
groupId="version"
|
||||
values={[
|
||||
{label: 'Before', value: '0.x'},
|
||||
{label: 'After', value: '1.x'},
|
||||
]}>
|
||||
|
||||
<TabItem value="0.x">
|
||||
scrollable
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId="0.x"
|
||||
>
|
||||
<TabPanel id="0.x" label="Before">
|
||||
|
||||
```dart
|
||||
final authSubscription = supabase.auth.onAuthStateChange((event, session) {
|
||||
@@ -123,9 +118,8 @@ final authSubscription = supabase.auth.onAuthStateChange((event, session) {
|
||||
authSubscription.data?.unsubscribe();
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
<TabItem value="1.x">
|
||||
</TabPanel>
|
||||
<TabPanel id="1.0x" label="After">
|
||||
|
||||
```dart
|
||||
final authSubscription = supabase.auth.onAuthStateChange.listen((data) {
|
||||
@@ -138,7 +132,7 @@ final authSubscription = supabase.auth.onAuthStateChange.listen((data) {
|
||||
authSubscription.cancel();
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
### Sign in with email and password
|
||||
@@ -146,65 +140,60 @@ authSubscription.cancel();
|
||||
The signIn() method has been deprecated in favor of more explicit method signatures to help with type hinting. Previously it was difficult for developers to know what they were missing (e.g., a lot of developers didn't realize they could use passwordless magic links).
|
||||
|
||||
<Tabs
|
||||
groupId="version"
|
||||
values={[
|
||||
{label: 'Before', value: '0.x'},
|
||||
{label: 'After', value: '1.x'},
|
||||
]}>
|
||||
|
||||
<TabItem value="0.x">
|
||||
scrollable
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId="0.x"
|
||||
>
|
||||
<TabPanel id="0.x" label="Before">
|
||||
|
||||
```dart
|
||||
await supabase.auth.signIn(email: email, password: password);
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
<TabItem value="1.x">
|
||||
</TabPanel>
|
||||
<TabPanel id="1.0x" label="After">
|
||||
|
||||
```dart
|
||||
await supabase.auth.signInWithPassword(email: email, password: password);
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
### Sign in with magic link
|
||||
|
||||
<Tabs
|
||||
groupId="version"
|
||||
values={[
|
||||
{label: 'Before', value: '0.x'},
|
||||
{label: 'After', value: '1.x'},
|
||||
]}>
|
||||
|
||||
<TabItem value="0.x">
|
||||
scrollable
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId="0.x"
|
||||
>
|
||||
<TabPanel id="0.x" label="Before">
|
||||
|
||||
```dart
|
||||
await supabase.auth.signIn(email: email);
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
<TabItem value="1.x">
|
||||
</TabPanel>
|
||||
<TabPanel id="1.0x" label="After">
|
||||
|
||||
```dart
|
||||
await supabase.auth.signInWithOtp(email: email);
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
### Sign in with a third-party OAuth provider
|
||||
|
||||
<Tabs
|
||||
groupId="version"
|
||||
values={[
|
||||
{label: 'Before', value: '0.x'},
|
||||
{label: 'After', value: '1.x'},
|
||||
]}>
|
||||
|
||||
<TabItem value="0.x">
|
||||
scrollable
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId="0.x"
|
||||
>
|
||||
<TabPanel id="0.x" label="Before">
|
||||
|
||||
```dart
|
||||
await supabase.auth.signInWithProvider(
|
||||
@@ -216,9 +205,8 @@ await supabase.auth.signInWithProvider(
|
||||
);
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
<TabItem value="1.x">
|
||||
</TabPanel>
|
||||
<TabPanel id="1.0x" label="After">
|
||||
|
||||
```dart
|
||||
await supabase.auth.signInWithOAuth(
|
||||
@@ -227,19 +215,18 @@ await supabase.auth.signInWithOAuth(
|
||||
);
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
### Sign in with phone
|
||||
|
||||
<Tabs
|
||||
groupId="version"
|
||||
values={[
|
||||
{label: 'Before', value: '0.x'},
|
||||
{label: 'After', value: '1.x'},
|
||||
]}>
|
||||
|
||||
<TabItem value="0.x">
|
||||
scrollable
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId="0.x"
|
||||
>
|
||||
<TabPanel id="0.x" label="Before">
|
||||
|
||||
```dart
|
||||
await supabase.auth.signIn(
|
||||
@@ -248,9 +235,8 @@ await supabase.auth.signIn(
|
||||
);
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
<TabItem value="1.x">
|
||||
</TabPanel>
|
||||
<TabPanel id="1.0x" label="After">
|
||||
|
||||
```dart
|
||||
await supabase.auth.signInWithPassword(
|
||||
@@ -259,27 +245,25 @@ await supabase.auth.signInWithPassword(
|
||||
);
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
### Sign in with phone using OTP
|
||||
|
||||
<Tabs
|
||||
groupId="version"
|
||||
values={[
|
||||
{label: 'Before', value: '0.x'},
|
||||
{label: 'After', value: '1.x'},
|
||||
]}>
|
||||
|
||||
<TabItem value="0.x">
|
||||
scrollable
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId="0.x"
|
||||
>
|
||||
<TabPanel id="0.x" label="Before">
|
||||
|
||||
```dart
|
||||
final res = await supabase.auth.signIn(phone: phone);
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
<TabItem value="1.x">
|
||||
</TabPanel>
|
||||
<TabPanel id="1.0x" label="After">
|
||||
|
||||
```dart
|
||||
await supabase.auth.signInWithOtp(
|
||||
@@ -294,19 +278,18 @@ await supabase.auth.verifyOTP(
|
||||
);
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
### Reset password for email
|
||||
|
||||
<Tabs
|
||||
groupId="version"
|
||||
values={[
|
||||
{label: 'Before', value: '0.x'},
|
||||
{label: 'After', value: '1.x'},
|
||||
]}>
|
||||
|
||||
<TabItem value="0.x">
|
||||
scrollable
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId="0.x"
|
||||
>
|
||||
<TabPanel id="0.x" label="Before">
|
||||
|
||||
```dart
|
||||
await supabase.auth.api.resetPasswordForEmail(
|
||||
@@ -316,9 +299,8 @@ await supabase.auth.api.resetPasswordForEmail(
|
||||
);
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
<TabItem value="1.x">
|
||||
</TabPanel>
|
||||
<TabPanel id="1.0x" label="After">
|
||||
|
||||
```dart
|
||||
await supabase.auth.resetPasswordForEmail(
|
||||
@@ -327,71 +309,66 @@ await supabase.auth.resetPasswordForEmail(
|
||||
);
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
### Get the user's current session
|
||||
|
||||
<Tabs
|
||||
groupId="version"
|
||||
values={[
|
||||
{label: 'Before', value: '0.x'},
|
||||
{label: 'After', value: '1.x'},
|
||||
]}>
|
||||
|
||||
<TabItem value="0.x">
|
||||
scrollable
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId="0.x"
|
||||
>
|
||||
<TabPanel id="0.x" label="Before">
|
||||
|
||||
```dart
|
||||
final session = supabase.auth.session();
|
||||
final session = supabase.auth.session();
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
<TabItem value="1.x">
|
||||
</TabPanel>
|
||||
<TabPanel id="1.0x" label="After">
|
||||
|
||||
```dart
|
||||
final Session? session = supabase.auth.currentSession;
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
### Get the logged-in user
|
||||
|
||||
<Tabs
|
||||
groupId="version"
|
||||
values={[
|
||||
{label: 'Before', value: '0.x'},
|
||||
{label: 'After', value: '1.x'},
|
||||
]}>
|
||||
|
||||
<TabItem value="0.x">
|
||||
scrollable
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId="0.x"
|
||||
>
|
||||
<TabPanel id="0.x" label="Before">
|
||||
|
||||
```dart
|
||||
final user = supabase.auth.user();
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
<TabItem value="1.x">
|
||||
</TabPanel>
|
||||
<TabPanel id="1.0x" label="After">
|
||||
|
||||
```dart
|
||||
final User? user = supabase.auth.currentUser;
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
### Update user data for a logged-in user
|
||||
|
||||
<Tabs
|
||||
groupId="version"
|
||||
values={[
|
||||
{label: 'Before', value: '0.x'},
|
||||
{label: 'After', value: '1.x'},
|
||||
]}>
|
||||
|
||||
<TabItem value="0.x">
|
||||
scrollable
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId="0.x"
|
||||
>
|
||||
<TabPanel id="0.x" label="Before">
|
||||
|
||||
```dart
|
||||
await supabase.auth.update(
|
||||
@@ -399,9 +376,8 @@ await supabase.auth.update(
|
||||
);
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
<TabItem value="1.x">
|
||||
</TabPanel>
|
||||
<TabPanel id="1.0x" label="After">
|
||||
|
||||
```dart
|
||||
await supabase.updateUser(
|
||||
@@ -411,7 +387,7 @@ await supabase.updateUser(
|
||||
);
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
## Data methods
|
||||
@@ -425,60 +401,56 @@ Also, calling `.execute()` at the end of the query was a requirement in v0, but
|
||||
### Insert without returning inserted data
|
||||
|
||||
<Tabs
|
||||
groupId="version"
|
||||
values={[
|
||||
{label: 'Before', value: '0.x'},
|
||||
{label: 'After', value: '1.x'},
|
||||
]}>
|
||||
|
||||
<TabItem value="0.x">
|
||||
scrollable
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId="0.x"
|
||||
>
|
||||
<TabPanel id="0.x" label="Before">
|
||||
|
||||
```dart
|
||||
await supabase
|
||||
.from('my_table')
|
||||
.insert(data, returning: ReturningOption.minimal)
|
||||
.execute();
|
||||
.from('my_table')
|
||||
.insert(data, returning: ReturningOption.minimal)
|
||||
.execute();
|
||||
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
<TabItem value="1.x">
|
||||
</TabPanel>
|
||||
<TabPanel id="1.0x" label="After">
|
||||
|
||||
```dart
|
||||
await supabase.from('my_table').insert(data);
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
### Insert with returning inserted data
|
||||
|
||||
<Tabs
|
||||
groupId="version"
|
||||
values={[
|
||||
{label: 'Before', value: '0.x'},
|
||||
{label: 'After', value: '1.x'},
|
||||
]}>
|
||||
|
||||
<TabItem value="0.x">
|
||||
scrollable
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId="0.x"
|
||||
>
|
||||
<TabPanel id="0.x" label="Before">
|
||||
|
||||
```dart
|
||||
final res = await supabase
|
||||
.from('my_table')
|
||||
.insert(data)
|
||||
.execute();
|
||||
.from('my_table')
|
||||
.insert(data)
|
||||
.execute();
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
<TabItem value="1.x">
|
||||
</TabPanel>
|
||||
<TabPanel id="1.0x" label="After">
|
||||
|
||||
```dart
|
||||
final insertedData = await supabase.from('my_table').insert(data).select();
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
## Realtime methods
|
||||
@@ -488,13 +460,12 @@ final insertedData = await supabase.from('my_table').insert(data).select();
|
||||
`.stream()` no longer needs the `.execute()` at the end. Also, filtering by `eq` is a lot easier now. `primaryKey` is now a named parameter to make it more obvious what to pass.
|
||||
|
||||
<Tabs
|
||||
groupId="version"
|
||||
values={[
|
||||
{label: 'Before', value: '0.x'},
|
||||
{label: 'After', value: '1.x'},
|
||||
]}>
|
||||
|
||||
<TabItem value="0.x">
|
||||
scrollable
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId="0.x"
|
||||
>
|
||||
<TabPanel id="0.x" label="Before">
|
||||
|
||||
```dart
|
||||
supabase.from('my_table:id=eq.120')
|
||||
@@ -502,9 +473,8 @@ supabase.from('my_table:id=eq.120')
|
||||
.listen();
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
<TabItem value="1.x">
|
||||
</TabPanel>
|
||||
<TabPanel id="1.0x" label="After">
|
||||
|
||||
```dart
|
||||
supabase.from('my_table')
|
||||
@@ -513,19 +483,18 @@ supabase.from('my_table')
|
||||
.listen();
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
### Subscribe
|
||||
|
||||
<Tabs
|
||||
groupId="version"
|
||||
values={[
|
||||
{label: 'Before', value: '0.x'},
|
||||
{label: 'After', value: '1.x'},
|
||||
]}>
|
||||
|
||||
<TabItem value="0.x">
|
||||
scrollable
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId="0.x"
|
||||
>
|
||||
<TabPanel id="0.x" label="Before">
|
||||
|
||||
```dart
|
||||
final subscription = supabase
|
||||
@@ -536,9 +505,8 @@ final subscription = supabase
|
||||
.subscribe();
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
<TabItem value="1.x">
|
||||
</TabPanel>
|
||||
<TabPanel id="1.0x" label="After">
|
||||
|
||||
```dart
|
||||
final channel = supabase.channel('*');
|
||||
@@ -551,31 +519,29 @@ channel.on(
|
||||
).subscribe();
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
### Unsubscribe
|
||||
|
||||
<Tabs
|
||||
groupId="version"
|
||||
values={[
|
||||
{label: 'Before', value: '0.x'},
|
||||
{label: 'After', value: '1.x'},
|
||||
]}>
|
||||
|
||||
<TabItem value="0.x">
|
||||
scrollable
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId="0.x"
|
||||
>
|
||||
<TabPanel id="0.x" label="Before">
|
||||
|
||||
```dart
|
||||
supabase.removeSubscription(subscription);
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
<TabItem value="1.x">
|
||||
</TabPanel>
|
||||
<TabPanel id="1.0x" label="After">
|
||||
|
||||
```dart
|
||||
await supabase.removeChannel(channel);
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
@@ -2,13 +2,14 @@
|
||||
id: intro
|
||||
slug: /
|
||||
sidebar_label: Supabase Dart Library
|
||||
title: Supabase Dart Library
|
||||
---
|
||||
|
||||
# Supabase Dart Library
|
||||
<Admonition type="caution">
|
||||
|
||||
:::caution
|
||||
You're viewing the docs for an older version of the `supabase-flutter` library.
|
||||
:::
|
||||
|
||||
</Admonition>
|
||||
|
||||
This reference documents every object and method available in Supabase's isomorphic Dart library, `supabase-dart`.
|
||||
|
||||
File renamed without changes.
Loaded 100 of 1811 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user