mirror of
https://github.com/supabase/supabase.git
synced 2026-10-07 02:15:05 +03:00
Update tabs for with-nextjs.mdx
This commit is contained in:
1 parent
a7b5876c71
commit
98277bce3d
9 files changed
+178
-86
No files matched your search
File renamed without changes.
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { getAnchor, removeAnchor } from './CustomMDX.utils'
|
||||
import { getAnchor, removeAnchor } from './CustomHTMLElements.utils'
|
||||
|
||||
const H3 = ({ children }) => {
|
||||
const anchor = getAnchor(children)
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { getAnchor, removeAnchor } from './CustomMDX.utils'
|
||||
import { getAnchor, removeAnchor } from './CustomHTMLElements.utils'
|
||||
|
||||
const H4 = ({ children }) => {
|
||||
const anchor = getAnchor(children)
|
||||
File renamed without changes.
@@ -0,0 +1,55 @@
|
||||
import UserManagementSQLTemplate from './user_management_quickstart_sql_template.mdx'
|
||||
|
||||
## Project set up
|
||||
|
||||
Before we start building we're going to set up our Database and API. This is as simple as starting a new Project in Supabase
|
||||
and then creating a "schema" inside the database.
|
||||
|
||||
### Create a project
|
||||
|
||||
1. Go to [app.supabase.com](https://app.supabase.com).
|
||||
1. Click on "New Project".
|
||||
1. Enter your project details.
|
||||
1. Wait for the new database to launch.
|
||||
|
||||
### Set up the database schema
|
||||
|
||||
Now we are going to set up the database schema. We can use the "User Management Starter" quickstart in the SQL Editor,
|
||||
or you can just copy/paste the SQL from below and run it yourself.
|
||||
|
||||
<Tabs
|
||||
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 />
|
||||
</video>
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="sql" label="SQL">
|
||||
|
||||
<UserManagementSQLTemplate />
|
||||
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
### Get the API Keys
|
||||
|
||||
Now that you've created some database tables, you are ready to insert data using the auto-generated API.
|
||||
We just need to get the URL and `anon` key from the API settings.
|
||||
|
||||
1. Go to the [Settings](https://app.supabase.com/project/_/settings) page in the Dashboard.
|
||||
2. Click **API** in the sidebar.
|
||||
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 />
|
||||
</video>
|
||||
@@ -0,0 +1,11 @@
|
||||
## Intro
|
||||
|
||||
This example provides the steps to build a basic user management app. It includes:
|
||||
|
||||
- Supabase [Database](/docs/guides/database): a Postgres database for storing your user data.
|
||||
- Supabase [Auth](/docs/guides/auth): users can sign in with magic links (no passwords, only email).
|
||||
- Supabase [Storage](/docs/guides/storage): users can upload a photo.
|
||||
- [Row Level Security](/docs/guides/auth#row-level-security): data is protected so that individuals can only access their own data.
|
||||
- Instant [APIs](/docs/guides/api): APIs will be automatically generated when you create your database tables.
|
||||
|
||||
By the end of this guide you'll have an app which allows users to login and update some basic profile details:
|
||||
@@ -0,0 +1,55 @@
|
||||
```sql
|
||||
-- Create a table for public profiles
|
||||
create table profiles (
|
||||
id uuid references auth.users not null primary key,
|
||||
updated_at timestamp with time zone,
|
||||
username text unique,
|
||||
full_name text,
|
||||
avatar_url text,
|
||||
website text,
|
||||
|
||||
constraint username_length check (char_length(username) >= 3)
|
||||
);
|
||||
-- Set up Row Level Security (RLS)
|
||||
-- See https://supabase.com/docs/guides/auth/row-level-security for more details.
|
||||
alter table profiles
|
||||
enable row level security;
|
||||
|
||||
create policy "Public profiles are viewable by everyone." on profiles
|
||||
for select using (true);
|
||||
|
||||
create policy "Users can insert their own profile." on profiles
|
||||
for insert with check (auth.uid() = id);
|
||||
|
||||
create policy "Users can update own profile." on profiles
|
||||
for update using (auth.uid() = id);
|
||||
|
||||
-- This trigger automatically creates a profile entry when a new user signs up via Supabase Auth.
|
||||
-- See https://supabase.com/docs/guides/auth/managing-user-data#using-triggers for more details.
|
||||
create function public.handle_new_user()
|
||||
returns trigger as $$
|
||||
begin
|
||||
insert into public.profiles (id, full_name, avatar_url)
|
||||
values (new.id, new.raw_user_meta_data->>'full_name', new.raw_user_meta_data->>'avatar_url');
|
||||
return new;
|
||||
end;
|
||||
$$ language plpgsql security definer;
|
||||
create trigger on_auth_user_created
|
||||
after insert on auth.users
|
||||
for each row execute procedure public.handle_new_user();
|
||||
|
||||
-- Set up Storage!
|
||||
insert into storage.buckets (id, name)
|
||||
values ('avatars', 'avatars');
|
||||
|
||||
-- Set up access controls for storage.
|
||||
-- See https://supabase.com/docs/guides/storage#policy-examples for more details.
|
||||
create policy "Avatar images are publicly accessible." on storage.objects
|
||||
for select using (bucket_id = 'avatars');
|
||||
|
||||
create policy "Anyone can upload an avatar." on storage.objects
|
||||
for insert with check (bucket_id = 'avatars');
|
||||
|
||||
create policy "Anyone can update their own avatar." on storage.objects
|
||||
for update using (auth.uid() = owner) with check (bucket_id = 'avatars');
|
||||
```
|
||||
@@ -4,15 +4,21 @@ import CodeBlock from './CodeBlock/CodeBlock'
|
||||
import ButtonCard from './ButtonCard'
|
||||
import Frameworks from './Frameworks'
|
||||
import AuthProviders from './AuthProviders'
|
||||
import { H3, H4 } from './CustomMDX'
|
||||
import { H3, H4 } from './CustomHTMLElements'
|
||||
|
||||
import QuickstartIntro from './MDX/quickstart_intro.mdx'
|
||||
import ProjectSetup from './MDX/project_setup.mdx'
|
||||
|
||||
const components = {
|
||||
Alert,
|
||||
ButtonCard,
|
||||
CodeBlock,
|
||||
Frameworks,
|
||||
AuthProviders,
|
||||
|
||||
QuickstartIntro,
|
||||
ProjectSetup,
|
||||
|
||||
Alert,
|
||||
Tabs,
|
||||
TabPanel: (props: any) => <Tabs.Panel {...props}>{props.children}</Tabs.Panel>,
|
||||
|
||||
|
||||
@@ -7,12 +7,11 @@ sidebar_label: 'Next.js'
|
||||
|
||||
import Tabs from '@theme/Tabs'
|
||||
import TabItem from '@theme/TabItem'
|
||||
import QuickstartIntro from './_partials/quickstart_intro.md'
|
||||
import ProjectSetup from './_partials/project_setup.mdx'
|
||||
|
||||
<QuickstartIntro />
|
||||
|
||||

|
||||

|
||||
|
||||
### Video Guide
|
||||
|
||||
@@ -41,28 +40,27 @@ We can use [`create-next-app`](https://nextjs.org/docs/getting-started) to initi
|
||||
an app called `supabase-nextjs`:
|
||||
|
||||
<Tabs
|
||||
groupId="language"
|
||||
defaultValue="js"
|
||||
values={[
|
||||
{label: 'JavaScript', value: 'js'},
|
||||
{label: 'TypeScript', value: 'ts'},
|
||||
]}>
|
||||
<TabItem value="js">
|
||||
scrollable
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId="js"
|
||||
>
|
||||
<TabPanel id="js" label="JavaScript">
|
||||
|
||||
```bash
|
||||
npx create-next-app@latest --use-npm supabase-nextjs
|
||||
cd supabase-nextjs
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="ts">
|
||||
</TabPanel>
|
||||
<TabPanel id="ts" label="TypeScript">
|
||||
|
||||
```bash
|
||||
npx create-next-app@latest --ts --use-npm supabase-nextjs
|
||||
cd supabase-nextjs
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
Then install the Supabase client library: [supabase-js](https://github.com/supabase/supabase-js)
|
||||
@@ -97,13 +95,12 @@ npm install @supabase/auth-helpers-react @supabase/auth-helpers-nextjs
|
||||
```
|
||||
|
||||
<Tabs
|
||||
groupId="language"
|
||||
defaultValue="js"
|
||||
values={[
|
||||
{label: 'JavaScript', value: 'js'},
|
||||
{label: 'TypeScript', value: 'ts'},
|
||||
]}>
|
||||
<TabItem value="js">
|
||||
scrollable
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId="js"
|
||||
>
|
||||
<TabPanel id="js" label="JavaScript">
|
||||
|
||||
Wrap your `pages/_app.js` component with the `SessionContextProvider` component:
|
||||
|
||||
@@ -127,8 +124,8 @@ function MyApp({ Component, pageProps }) {
|
||||
export default MyApp
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="ts">
|
||||
</TabPanel>
|
||||
<TabPanel id="ts" label="TypeScript">
|
||||
|
||||
Wrap your `pages/_app.tsx` component with the `SessionContextProvider` component:
|
||||
|
||||
@@ -160,7 +157,7 @@ export default MyApp
|
||||
|
||||
See the [Auth Helpers docs](/docs/guides/auth/auth-helpers/nextjs#usage-with-typescript) for more details on usage with TypeScript.
|
||||
|
||||
</TabItem>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
#### Supabase Auth UI
|
||||
@@ -186,11 +183,7 @@ const Home = () => {
|
||||
return (
|
||||
<div className="container" style={{ padding: '50px 0 100px 0' }}>
|
||||
{!session ? (
|
||||
<Auth
|
||||
supabaseClient={supabase}
|
||||
appearance={{ theme: ThemeSupa }}
|
||||
theme="dark"
|
||||
/>
|
||||
<Auth supabaseClient={supabase} appearance={{ theme: ThemeSupa }} theme="dark" />
|
||||
) : (
|
||||
<p>Account page will go here.</p>
|
||||
)}
|
||||
@@ -206,13 +199,12 @@ export default Home
|
||||
After a user is signed in we can allow them to edit their profile details and manage their account.
|
||||
|
||||
<Tabs
|
||||
groupId="language"
|
||||
defaultValue="js"
|
||||
values={[
|
||||
{label: 'JavaScript', value: 'js'},
|
||||
{label: 'TypeScript', value: 'ts'},
|
||||
]}>
|
||||
<TabItem value="js">
|
||||
scrollable
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId="js"
|
||||
>
|
||||
<TabPanel id="js" label="JavaScript">
|
||||
|
||||
Let's create a new component for that called `Account.js` within a `components` folder.
|
||||
|
||||
@@ -318,10 +310,7 @@ export default function Account({ session }) {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button
|
||||
className="button block"
|
||||
onClick={() => supabase.auth.signOut()}
|
||||
>
|
||||
<button className="button block" onClick={() => supabase.auth.signOut()}>
|
||||
Sign Out
|
||||
</button>
|
||||
</div>
|
||||
@@ -330,18 +319,14 @@ export default function Account({ session }) {
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="ts">
|
||||
</TabPanel>
|
||||
<TabPanel id="ts" label="TypeScript">
|
||||
|
||||
Let's create a new component for that called `Account.tsx` within a `components` folder.
|
||||
|
||||
```tsx title="components/Account.tsx"
|
||||
import { useState, useEffect } from 'react'
|
||||
import {
|
||||
useUser,
|
||||
useSupabaseClient,
|
||||
Session,
|
||||
} from '@supabase/auth-helpers-react'
|
||||
import { useUser, useSupabaseClient, Session } from '@supabase/auth-helpers-react'
|
||||
import { Database } from '../utils/database.types'
|
||||
type Profiles = Database['public']['Tables']['profiles']['Row']
|
||||
|
||||
@@ -453,10 +438,7 @@ export default function Account({ session }: { session: Session }) {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button
|
||||
className="button block"
|
||||
onClick={() => supabase.auth.signOut()}
|
||||
>
|
||||
<button className="button block" onClick={() => supabase.auth.signOut()}>
|
||||
Sign Out
|
||||
</button>
|
||||
</div>
|
||||
@@ -465,7 +447,7 @@ export default function Account({ session }: { session: Session }) {
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
### Launch!
|
||||
@@ -485,11 +467,7 @@ const Home = () => {
|
||||
return (
|
||||
<div className="container" style={{ padding: '50px 0 100px 0' }}>
|
||||
{!session ? (
|
||||
<Auth
|
||||
supabaseClient={supabase}
|
||||
appearance={{ theme: ThemeSupa }}
|
||||
theme="dark"
|
||||
/>
|
||||
<Auth supabaseClient={supabase} appearance={{ theme: ThemeSupa }} theme="dark" />
|
||||
) : (
|
||||
// highlight-next-line
|
||||
<Account session={session} />
|
||||
@@ -519,13 +497,12 @@ photos and videos.
|
||||
Let's create an avatar widget for the user so that they can upload a profile photo. We can start by creating a new component:
|
||||
|
||||
<Tabs
|
||||
groupId="language"
|
||||
defaultValue="js"
|
||||
values={[
|
||||
{label: 'JavaScript', value: 'js'},
|
||||
{label: 'TypeScript', value: 'ts'},
|
||||
]}>
|
||||
<TabItem value="js">
|
||||
scrollable
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId="js"
|
||||
>
|
||||
<TabPanel id="js" label="JavaScript">
|
||||
|
||||
```jsx title="components/Avatar.js"
|
||||
import React, { useEffect, useState } from 'react'
|
||||
@@ -542,9 +519,7 @@ export default function Avatar({ uid, url, size, onUpload }) {
|
||||
|
||||
async function downloadImage(path) {
|
||||
try {
|
||||
const { data, error } = await supabase.storage
|
||||
.from('avatars')
|
||||
.download(path)
|
||||
const { data, error } = await supabase.storage.from('avatars').download(path)
|
||||
if (error) {
|
||||
throw error
|
||||
}
|
||||
@@ -595,10 +570,7 @@ export default function Avatar({ uid, url, size, onUpload }) {
|
||||
style={{ height: size, width: size }}
|
||||
/>
|
||||
) : (
|
||||
<div
|
||||
className="avatar no-image"
|
||||
style={{ height: size, width: size }}
|
||||
/>
|
||||
<div className="avatar no-image" style={{ height: size, width: size }} />
|
||||
)}
|
||||
<div style={{ width: size }}>
|
||||
<label className="button primary block" htmlFor="single">
|
||||
@@ -621,8 +593,8 @@ export default function Avatar({ uid, url, size, onUpload }) {
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="ts">
|
||||
</TabPanel>
|
||||
<TabPanel id="ts" label="TypeScript">
|
||||
|
||||
```tsx title="components/Avatar.tsx"
|
||||
import React, { useEffect, useState } from 'react'
|
||||
@@ -651,9 +623,7 @@ export default function Avatar({
|
||||
|
||||
async function downloadImage(path: string) {
|
||||
try {
|
||||
const { data, error } = await supabase.storage
|
||||
.from('avatars')
|
||||
.download(path)
|
||||
const { data, error } = await supabase.storage.from('avatars').download(path)
|
||||
if (error) {
|
||||
throw error
|
||||
}
|
||||
@@ -664,9 +634,7 @@ export default function Avatar({
|
||||
}
|
||||
}
|
||||
|
||||
const uploadAvatar: React.ChangeEventHandler<HTMLInputElement> = async (
|
||||
event
|
||||
) => {
|
||||
const uploadAvatar: React.ChangeEventHandler<HTMLInputElement> = async (event) => {
|
||||
try {
|
||||
setUploading(true)
|
||||
|
||||
@@ -706,10 +674,7 @@ export default function Avatar({
|
||||
style={{ height: size, width: size }}
|
||||
/>
|
||||
) : (
|
||||
<div
|
||||
className="avatar no-image"
|
||||
style={{ height: size, width: size }}
|
||||
/>
|
||||
<div className="avatar no-image" style={{ height: size, width: size }} />
|
||||
)}
|
||||
<div style={{ width: size }}>
|
||||
<label className="button primary block" htmlFor="single">
|
||||
@@ -732,7 +697,7 @@ export default function Avatar({
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
### Add the new widget
|
||||
|
||||
Reference in new issue
Block a user