Delete old files and create new nextjs+supabase project
This commit is contained in:
20
app/auth/callback/route.ts
Normal file
20
app/auth/callback/route.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
import { NextResponse } from "next/server";
|
||||
import { cookies } from "next/headers";
|
||||
|
||||
export async function GET(request: Request) {
|
||||
// The `/auth/callback` route is required for the server-side auth flow implemented
|
||||
// by the Auth Helpers package. It exchanges an auth code for the user's session.
|
||||
// https://supabase.com/docs/guides/auth/auth-helpers/nextjs#managing-sign-in-with-code-exchange
|
||||
const requestUrl = new URL(request.url);
|
||||
const code = requestUrl.searchParams.get("code");
|
||||
|
||||
if (code) {
|
||||
const cookieStore = cookies();
|
||||
const supabase = createClient(cookieStore);
|
||||
await supabase.auth.exchangeCodeForSession(code);
|
||||
}
|
||||
|
||||
// URL to redirect to after sign in process completes
|
||||
return NextResponse.redirect(requestUrl.origin);
|
||||
}
|
||||
BIN
app/favicon.ico
Normal file
BIN
app/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
42
app/globals.css
Normal file
42
app/globals.css
Normal file
@@ -0,0 +1,42 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 200 20% 98%;
|
||||
--btn-background: 200 10% 91%;
|
||||
--btn-background-hover: 200 10% 89%;
|
||||
--foreground: 200 50% 3%;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--background: 200 50% 3%;
|
||||
--btn-background: 200 10% 9%;
|
||||
--btn-background-hover: 200 10% 12%;
|
||||
--foreground: 200 20% 96%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-foreground/20;
|
||||
}
|
||||
}
|
||||
|
||||
.animate-in {
|
||||
animation: animateIn 0.3s ease 0.15s both;
|
||||
}
|
||||
|
||||
@keyframes animateIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,28 @@
|
||||
import type { Metadata } from 'next'
|
||||
import { GeistSans } from "geist/font/sans";
|
||||
import "./globals.css";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Stan Runge',
|
||||
description: 'Stan Runge',
|
||||
}
|
||||
const defaultUrl = process.env.VERCEL_URL
|
||||
? `https://${process.env.VERCEL_URL}`
|
||||
: "http://localhost:3000";
|
||||
|
||||
export const metadata = {
|
||||
metadataBase: new URL(defaultUrl),
|
||||
title: "Next.js and Supabase Starter Kit",
|
||||
description: "The fastest way to build apps with Next.js and Supabase",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>{children}</body>
|
||||
<html lang="en" className={GeistSans.className}>
|
||||
<body className="bg-background text-foreground">
|
||||
<main className="min-h-screen flex flex-col items-center">
|
||||
{children}
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
118
app/login/page.tsx
Normal file
118
app/login/page.tsx
Normal file
@@ -0,0 +1,118 @@
|
||||
import Link from "next/link";
|
||||
import { headers, cookies } from "next/headers";
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export default function Login({
|
||||
searchParams,
|
||||
}: {
|
||||
searchParams: { message: string };
|
||||
}) {
|
||||
const signIn = async (formData: FormData) => {
|
||||
"use server";
|
||||
|
||||
const email = formData.get("email") as string;
|
||||
const password = formData.get("password") as string;
|
||||
const cookieStore = cookies();
|
||||
const supabase = createClient(cookieStore);
|
||||
|
||||
const { error } = await supabase.auth.signInWithPassword({
|
||||
email,
|
||||
password,
|
||||
});
|
||||
|
||||
if (error) {
|
||||
return redirect("/login?message=Could not authenticate user");
|
||||
}
|
||||
|
||||
return redirect("/");
|
||||
};
|
||||
|
||||
const signUp = async (formData: FormData) => {
|
||||
"use server";
|
||||
|
||||
const origin = headers().get("origin");
|
||||
const email = formData.get("email") as string;
|
||||
const password = formData.get("password") as string;
|
||||
const cookieStore = cookies();
|
||||
const supabase = createClient(cookieStore);
|
||||
|
||||
const { error } = await supabase.auth.signUp({
|
||||
email,
|
||||
password,
|
||||
options: {
|
||||
emailRedirectTo: `${origin}/auth/callback`,
|
||||
},
|
||||
});
|
||||
|
||||
if (error) {
|
||||
return redirect("/login?message=Could not authenticate user");
|
||||
}
|
||||
|
||||
return redirect("/login?message=Check email to continue sign in process");
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex-1 flex flex-col w-full px-8 sm:max-w-md justify-center gap-2">
|
||||
<Link
|
||||
href="/"
|
||||
className="absolute left-8 top-8 py-2 px-4 rounded-md no-underline text-foreground bg-btn-background hover:bg-btn-background-hover flex items-center group text-sm"
|
||||
>
|
||||
<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="mr-2 h-4 w-4 transition-transform group-hover:-translate-x-1"
|
||||
>
|
||||
<polyline points="15 18 9 12 15 6" />
|
||||
</svg>{" "}
|
||||
Back
|
||||
</Link>
|
||||
|
||||
<form
|
||||
className="animate-in flex-1 flex flex-col w-full justify-center gap-2 text-foreground"
|
||||
action={signIn}
|
||||
>
|
||||
<label className="text-md" htmlFor="email">
|
||||
Email
|
||||
</label>
|
||||
<input
|
||||
className="rounded-md px-4 py-2 bg-inherit border mb-6"
|
||||
name="email"
|
||||
placeholder="you@example.com"
|
||||
required
|
||||
/>
|
||||
<label className="text-md" htmlFor="password">
|
||||
Password
|
||||
</label>
|
||||
<input
|
||||
className="rounded-md px-4 py-2 bg-inherit border mb-6"
|
||||
type="password"
|
||||
name="password"
|
||||
placeholder="••••••••"
|
||||
required
|
||||
/>
|
||||
<button className="bg-green-700 rounded-md px-4 py-2 text-foreground mb-2">
|
||||
Sign In
|
||||
</button>
|
||||
<button
|
||||
formAction={signUp}
|
||||
className="border border-foreground/20 rounded-md px-4 py-2 text-foreground mb-2"
|
||||
>
|
||||
Sign Up
|
||||
</button>
|
||||
{searchParams?.message && (
|
||||
<p className="mt-4 p-4 bg-foreground/10 text-foreground text-center">
|
||||
{searchParams.message}
|
||||
</p>
|
||||
)}
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
BIN
app/opengraph-image.png
Normal file
BIN
app/opengraph-image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 283 KiB |
60
app/page.tsx
60
app/page.tsx
@@ -1,7 +1,57 @@
|
||||
export default function Home() {
|
||||
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";
|
||||
import { cookies } from "next/headers";
|
||||
|
||||
export default async function Index() {
|
||||
const cookieStore = cookies();
|
||||
|
||||
const canInitSupabaseClient = () => {
|
||||
// This function is just for the interactive tutorial.
|
||||
// Feel free to remove it once you have Supabase connected.
|
||||
try {
|
||||
createClient(cookieStore);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const isSupabaseConnected = canInitSupabaseClient();
|
||||
|
||||
return (
|
||||
<main className={"bg-slate-800"}>
|
||||
<h1>Stan Runge</h1>
|
||||
</main>
|
||||
)
|
||||
<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">
|
||||
<DeployButton />
|
||||
{isSupabaseConnected && <AuthButton />}
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<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"
|
||||
rel="noreferrer"
|
||||
>
|
||||
Supabase
|
||||
</a>
|
||||
</p>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
BIN
app/twitter-image.png
Normal file
BIN
app/twitter-image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 283 KiB |
Reference in New Issue
Block a user