Skip to content

Commit

Permalink
add dynamic landing page to step the user through connecting to supabase
Browse files Browse the repository at this point in the history
  • Loading branch information
dijonmusters committed Oct 20, 2023
1 parent 9911dc8 commit 78698d4
Show file tree
Hide file tree
Showing 19 changed files with 442 additions and 287 deletions.
48 changes: 13 additions & 35 deletions examples/with-supabase/README.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
<a href="https://demo-nextjs-with-supabase.vercel.app/">
<img alt="Next.js 13 and app template Router-ready Supabase starter kit." src="https://demo-nextjs-with-supabase.vercel.app/opengraph-image.png">
<h1 align="center">Supabase starter kit</h1>
<img alt="Next.js and Supabase Starter Kit - the fastest way to build apps with Next.js and Supabase" src="https://demo-nextjs-with-supabase.vercel.app/opengraph-image.png">
<h1 align="center">Next.js and Supabase Starter Kit</h1>
</a>

<p align="center">
This starter configures Supabase Auth to use cookies, making the user's session available throughout the entire Next.js app - Client Components, Server Components, Route Handlers, Server Actions and Middleware.
The fastest way to build apps with Next.js and Supabase
</p>

<p align="center">
<a href="#features"><strong>Features</strong></a> ·
<a href="#demo"><strong>Demo</strong></a> ·
<a href="#deploy-to-vercel"><strong>Deploy to Vercel</strong></a> ·
<a href="#clone-and-run-locally"><strong>Clone and run locally</strong></a> ·
<a href="#how-to-use"><strong>How to use</strong></a> ·
<a href="#feedback-and-issues"><strong>Feedback and issues</strong></a>
<a href="#more-supabase-examples"><strong>More Examples</strong></a>
</p>
<br/>

## Features

- [Next.js App router ready](https://nextjs.org) App Router
- Client Components examples
- React Server Components (RSCs) examples
- Route Handlers examples
- Server Actions examples
- [supabase-js](https://supabase.com/docs/reference/javascript). Supabase's
isomorphic JavaScript library.
- [Supabase Auth](https://supabase.com/auth) using cookies, making the user's session available throughout the entire Next.js app, for both client and server.
- Works across the entire [Next.js](https://nextjs.org) stack
- App Router
- Pages Router
- Middleware
- Client
- Server
- It just works!
- supabase-ssr. A package to configure Supabase Auth to use cookies
- Styling with [Tailwind CSS](https://tailwindcss.com)
- Optional deployment with [Supabase Vercel Integration and Vercel deploy](#deploy-your-own)
- Environment variables automatically assigned to Vercel project
Expand All @@ -45,7 +45,7 @@ After installation of the Supabase integration, all relevant environment variabl

The above will also clone the Starter kit to your GitHub, you can clone that locally and develop locally.

If you wish to just develop locally and not deploy to Vercel, [follow the steps below](#how-to-use).
If you wish to just develop locally and not deploy to Vercel, [follow the steps below](#clone-and-run-locally).

## Clone and run locally

Expand Down Expand Up @@ -82,27 +82,6 @@ If you wish to just develop locally and not deploy to Vercel, [follow the steps

> Check out [the docs for Local Development](https://supabase.com/docs/guides/getting-started/local-development) to also run Supabase locally.
## How to use

There are a variety of example files for you to copy and build your app with in the starter kit.

### Create a Supabase client

Check out the [`/app/_examples`](./app/_examples/) folder for an example of creating a Supabase client in:

- [Client Components](./app/_examples/client-component/page.tsx)
- [Server Components](./app/_examples/server-component/page.tsx)
- [Route Handlers](./app/_examples/route-handler/route.ts)
- [Server Actions](./app/_examples/server-action/page.tsx)

### Create `todo` table and seed with data (optional)

Navigate to [your project's SQL Editor](https://app.supabase.com/project/_/sql), click `New query`, paste the contents of the [init.sql](./supabase/migrations/20230618024722_init.sql) file and click `RUN`.

This will create a basic `todos` table, enable Row Level Security (RLS), and write RLS policies enabling `select` and `insert` actions for `authenticated` users.

To seed your `todos` table with some dummy data, run the contents of the [seed.sql](./supabase/seed.sql) file.

## Feedback and issues

Please file feedback and issues over on the [Supabase GitHub org](https://github.com/supabase/supabase/issues/new/choose).
Expand All @@ -112,4 +91,3 @@ Please file feedback and issues over on the [Supabase GitHub org](https://github
- [Next.js Subscription Payments Starter](https://github.com/vercel/nextjs-subscription-payments)
- [Cookie-based Auth and the Next.js 13 App Router (free course)](https://youtube.com/playlist?list=PL5S4mPUpp4OtMhpnp93EFSo42iQ40XjbF)
- [Supabase Auth and the Next.js App Router](https://github.com/supabase/supabase/tree/master/examples/auth/nextjs)
- [Next.js Auth Helpers Docs](https://supabase.com/docs/guides/auth/auth-helpers/nextjs)
8 changes: 4 additions & 4 deletions examples/with-supabase/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import './globals.css'

export const metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
title: 'Next.js and Supabase Starter Kit',
description: 'The fastest way to build apps with Next.js and Supabase',
}

export default function RootLayout({
Expand All @@ -12,8 +12,8 @@ export default function RootLayout({
}) {
return (
<html lang="en">
<body>
<main className="min-h-screen bg-background text-foreground flex flex-col items-center">
<body className="bg-background text-foreground">
<main className="min-h-screen flex flex-col items-center">
{children}
</main>
</body>
Expand Down
4 changes: 2 additions & 2 deletions examples/with-supabase/app/login/messages.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ export default function Messages() {
return (
<>
{error && (
<p className="mt-4 p-4 bg-neutral-900 text-neutral-300 text-center">
<p className="mt-4 p-4 bg-foreground/10 text-foreground text-center">
{error}
</p>
)}
{message && (
<p className="mt-4 p-4 bg-neutral-900 text-neutral-300 text-center">
<p className="mt-4 p-4 bg-foreground/10 text-foreground text-center">
{message}
</p>
)}
Expand Down
4 changes: 2 additions & 2 deletions examples/with-supabase/app/login/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,12 @@ export default function Login() {
placeholder="••••••••"
required
/>
<button className="bg-green-700 rounded px-4 py-2 text-white mb-2">
<button className="bg-green-700 rounded-md px-4 py-2 text-foreground mb-2">
Sign In
</button>
<button
formAction="/auth/sign-up"
className="border border-gray-700 rounded px-4 py-2 text-foreground mb-2"
className="border border-foreground/20 rounded-md px-4 py-2 text-foreground mb-2"
>
Sign Up
</button>
Expand Down
204 changes: 35 additions & 169 deletions examples/with-supabase/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,187 +1,53 @@
import Link from 'next/link'
import LogoutButton from '../components/LogoutButton'
import SupabaseLogo from '../components/SupabaseLogo'
import NextJsLogo from '../components/NextJsLogo'
import DeployButton from '../components/DeployButton'
import AuthButton from '../components/AuthButton'
import { createClient } from '@/utils/supabase/server'
import ConnectSupabaseSteps from '@/components/ConnectSupabaseSteps'
import SignUpUserSteps from '@/components/SignUpUserSteps'
import Header from '@/components/Header'

export const dynamic = 'force-dynamic'

const resources = [
{
title: 'Cookie-based Auth and the Next.js App Router',
subtitle:
'This free course by Jon Meyers, shows you how to configure Supabase Auth to use cookies, and steps through some common patterns.',
url: 'https://youtube.com/playlist?list=PL5S4mPUpp4OtMhpnp93EFSo42iQ40XjbF',
icon: 'M7 4V20M17 4V20M3 8H7M17 8H21M3 12H21M3 16H7M17 16H21M4 20H20C20.5523 20 21 19.5523 21 19V5C21 4.44772 20.5523 4 20 4H4C3.44772 4 3 4.44772 3 5V19C3 19.5523 3.44772 20 4 20Z',
},
{
title: 'Supabase Next.js App Router Example',
subtitle:
'Want to see a code example containing some common patterns with Next.js and Supabase? Check out this repo!',
url: 'https://github.com/supabase/supabase/tree/master/examples/auth/nextjs',
icon: 'M10 20L14 4M18 8L22 12L18 16M6 16L2 12L6 8',
},
{
title: 'Supabase Auth Helpers Docs',
subtitle:
'This template has configured Supabase Auth to use cookies for you, but the docs are a great place to learn more.',
url: 'https://supabase.com/docs/guides/auth/auth-helpers/nextjs',
icon: 'M12 6.25278V19.2528M12 6.25278C10.8321 5.47686 9.24649 5 7.5 5C5.75351 5 4.16789 5.47686 3 6.25278V19.2528C4.16789 18.4769 5.75351 18 7.5 18C9.24649 18 10.8321 18.4769 12 19.2528M12 6.25278C13.1679 5.47686 14.7535 5 16.5 5C18.2465 5 19.8321 5.47686 21 6.25278V19.2528C19.8321 18.4769 18.2465 18 16.5 18C14.7535 18 13.1679 18.4769 12 19.2528',
},
]

const examples = [
{ type: 'Client Components', src: 'app/_examples/client-component/page.tsx' },
{ type: 'Server Components', src: 'app/_examples/server-component/page.tsx' },
{ type: 'Server Actions', src: 'app/_examples/server-action/page.tsx' },
{ type: 'Route Handlers', src: 'app/_examples/route-handler.ts' },
]
const canInitSupabaseClient = () => {
try {
createClient()
return true
} catch (e) {
return false
}
}

export default async function Index() {
const supabase = createClient()

const {
data: { user },
} = await supabase.auth.getUser()
const isSupabaseConnected = canInitSupabaseClient()

return (
<div className="w-full flex flex-col items-center">
<div className="flex-1 w-full flex flex-col gap-20 items-center">
<nav className="w-full flex justify-center border-b border-b-foreground/10 h-16">
<div className="w-full max-w-4xl flex justify-between items-center p-3 text-sm text-foreground">
<div className="w-full max-w-4xl flex justify-between items-center p-3 text-sm">
<DeployButton />
{user ? (
<div className="flex items-center gap-4">
Hey, {user.email}!
<LogoutButton />
</div>
) : (
<Link
href="/login"
className="py-2 px-3 flex rounded-md no-underline bg-btn-background hover:bg-btn-background-hover"
>
Login
</Link>
)}
{isSupabaseConnected && <AuthButton />}
</div>
</nav>

<div className="animate-in flex flex-col gap-14 opacity-0 max-w-4xl px-3 py-16 lg:py-24 text-foreground">
<div className="flex flex-col items-center mb-4 lg:mb-12">
<div className="flex gap-8 justify-center items-center">
<Link href="https://supabase.com/" target="_blank">
<SupabaseLogo />
</Link>
<span className="border-l rotate-45 h-6" />
<NextJsLogo />
</div>
<h1 className="sr-only">Supabase and Next.js Starter Template</h1>
<p className="text-3xl lg:text-4xl !leading-tight mx-auto max-w-xl text-center my-12">
The fastest way to start building apps with{' '}
<strong>Supabase</strong> and <strong>Next.js</strong>
</p>
<div className="bg-foreground py-3 px-6 rounded-lg font-mono text-sm text-background">
Get started by editing <strong>app/page.tsx</strong>
</div>
</div>

<div className="w-full p-[1px] bg-gradient-to-r from-transparent via-foreground/10 to-transparent" />

<div className="flex flex-col gap-8 text-foreground">
<h2 className="text-lg font-bold text-center">
Everything you need to get started
</h2>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-4">
{resources.map(({ title, subtitle, url, icon }) => (
<a
key={title}
className="relative flex flex-col group rounded-lg border p-6 hover:border-foreground"
href={url}
target="_blank"
rel="noreferrer"
>
<h3 className="font-bold mb-2 min-h-[40px] lg:min-h-[60px]">
{title}
</h3>
<div className="flex flex-col grow gap-4 justify-between">
<p className="text-sm opacity-70">{subtitle}</p>
<div className="flex justify-between items-center">
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="opacity-80 group-hover:opacity-100"
>
<path
d={icon}
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>

<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="ml-2 h-4 w-4 opacity-0 -translate-x-2 group-hover:translate-x-0 group-hover:opacity-100 transition-all"
>
<polyline points="9 18 15 12 9 6" />
</svg>
</div>
</div>
</a>
))}
</div>
</div>

<div className="flex flex-col gap-8 text-foreground">
<div className="grid gap-2 justify-center mx-auto text-center">
<h2 className="text-lg font-bold text-center">Examples</h2>
<p className="text-sm">
Look in the <code>_examples</code> folder to see how to create a
Supabase client in all the different contexts.
</p>
</div>
<div className="w-full justify-center border rounded-lg overflow-hidden">
{examples.map(({ type, src }) => (
<div
key={type}
className="w-full grid grid-cols-3 border-b last:border-b-0 text-sm"
>
<div className="flex items-center font-bold p-4 min-h-12 w-full">
{type}
</div>
<div className="col-span-2 border-l p-4 flex items-center">
<code className="text-sm whitespace-pre-wrap">{src}</code>
</div>
</div>
))}
</div>
</div>

<div className="flex justify-center text-center text-xs">
<p>
Powered by{' '}
<Link
href="https://supabase.com/"
target="_blank"
className="font-bold"
>
Supabase
</Link>
</p>
</div>
<div className="animate-in flex-1 flex flex-col gap-20 opacity-0 max-w-4xl px-3">
<Header />
<main className="flex-1 flex flex-col gap-6">
<h2 className="font-bold text-4xl mb-4">Next steps</h2>
{isSupabaseConnected ? <SignUpUserSteps /> : <ConnectSupabaseSteps />}
</main>
</div>

<footer className="w-full border-t border-t-foreground/10 p-8 flex justify-center text-center text-xs">
<p>
Powered by{' '}
<a
href="https://supabase.com/?utm_source=create-next-app&utm_medium=template&utm_term=nextjs"
target="_blank"
className="font-bold hover:underline"
>
Supabase
</a>
</p>
</footer>
</div>
)
}
Binary file added examples/with-supabase/app/twitter-image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 28 additions & 0 deletions examples/with-supabase/components/AuthButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { createClient } from '@/utils/supabase/server'
import Link from 'next/link'

export default async function AuthButton() {
const supabase = createClient()

const {
data: { user },
} = await supabase.auth.getUser()

return user ? (
<div className="flex items-center gap-4">
Hey, {user.email}!
<form action="/auth/sign-out" method="post">
<button className="py-2 px-4 rounded-md no-underline bg-btn-background hover:bg-btn-background-hover">
Logout
</button>
</form>
</div>
) : (
<Link
href="/login"
className="py-2 px-3 flex rounded-md no-underline bg-btn-background hover:bg-btn-background-hover"
>
Login
</Link>
)
}
Loading

0 comments on commit 78698d4

Please sign in to comment.