Initial commit from Create Next App

This commit is contained in:
Kaur Laanemäe
2025-04-30 13:29:42 +03:00
commit 60d6adcd94
53 changed files with 5495 additions and 0 deletions

View File

@@ -0,0 +1,61 @@
"use client";
import { useState } from "react";
import { Button } from "../ui/button";
const CopyIcon = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
</svg>
);
const CheckIcon = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<polyline points="20 6 9 17 4 12"></polyline>
</svg>
);
export function CodeBlock({ code }: { code: string }) {
const [icon, setIcon] = useState(CopyIcon);
const copy = async () => {
await navigator?.clipboard?.writeText(code);
setIcon(CheckIcon);
setTimeout(() => setIcon(CopyIcon), 2000);
};
return (
<pre className="bg-muted rounded-md p-6 my-6 relative">
<Button
size="icon"
onClick={copy}
variant={"outline"}
className="absolute right-2 top-2"
>
{icon}
</Button>
<code className="text-xs p-3">{code}</code>
</pre>
);
}

View File

@@ -0,0 +1,62 @@
import { TutorialStep } from "./tutorial-step";
export default function ConnectSupabaseSteps() {
return (
<ol className="flex flex-col gap-6">
<TutorialStep title="Create Supabase project">
<p>
Head over to{" "}
<a
href="https://app.supabase.com/project/_/settings/api"
target="_blank"
className="font-bold hover:underline text-foreground/80"
rel="noreferrer"
>
database.new
</a>{" "}
and create a new Supabase project.
</p>
</TutorialStep>
<TutorialStep title="Declare environment variables">
<p>
Rename the{" "}
<span className="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-xs font-medium text-secondary-foreground border">
.env.example
</span>{" "}
file in your Next.js app to{" "}
<span className="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-xs font-medium text-secondary-foreground border">
.env.local
</span>{" "}
and populate with values from{" "}
<a
href="https://app.supabase.com/project/_/settings/api"
target="_blank"
className="font-bold hover:underline text-foreground/80"
rel="noreferrer"
>
your Supabase project's API Settings
</a>
.
</p>
</TutorialStep>
<TutorialStep title="Restart your Next.js development server">
<p>
You may need to quit your Next.js development server and run{" "}
<span className="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-xs font-medium text-secondary-foreground border">
npm run dev
</span>{" "}
again to load the new environment variables.
</p>
</TutorialStep>
<TutorialStep title="Refresh the page">
<p>
You may need to refresh the page for Next.js to load the new
environment variables.
</p>
</TutorialStep>
</ol>
);
}

View File

@@ -0,0 +1,96 @@
import { TutorialStep } from "./tutorial-step";
import { CodeBlock } from "./code-block";
const create = `create table notes (
id bigserial primary key,
title text
);
insert into notes(title)
values
('Today I created a Supabase project.'),
('I added some data and queried it from Next.js.'),
('It was awesome!');
`.trim();
const server = `import { createClient } from '@/utils/supabase/server'
export default async function Page() {
const supabase = await createClient()
const { data: notes } = await supabase.from('notes').select()
return <pre>{JSON.stringify(notes, null, 2)}</pre>
}
`.trim();
const client = `'use client'
import { createClient } from '@/utils/supabase/client'
import { useEffect, useState } from 'react'
export default function Page() {
const [notes, setNotes] = useState<any[] | null>(null)
const supabase = createClient()
useEffect(() => {
const getData = async () => {
const { data } = await supabase.from('notes').select()
setNotes(data)
}
getData()
}, [])
return <pre>{JSON.stringify(notes, null, 2)}</pre>
}
`.trim();
export default function FetchDataSteps() {
return (
<ol className="flex flex-col gap-6">
<TutorialStep title="Create some tables and insert some data">
<p>
Head over to the{" "}
<a
href="https://supabase.com/dashboard/project/_/editor"
className="font-bold hover:underline text-foreground/80"
target="_blank"
rel="noreferrer"
>
Table Editor
</a>{" "}
for your Supabase project to create a table and insert some example
data. If you're stuck for creativity, you can copy and paste the
following into the{" "}
<a
href="https://supabase.com/dashboard/project/_/sql/new"
className="font-bold hover:underline text-foreground/80"
target="_blank"
rel="noreferrer"
>
SQL Editor
</a>{" "}
and click RUN!
</p>
<CodeBlock code={create} />
</TutorialStep>
<TutorialStep title="Query Supabase data from Next.js">
<p>
To create a Supabase client and query data from an Async Server
Component, create a new page.tsx file at{" "}
<span className="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-xs font-medium text-secondary-foreground border">
/app/notes/page.tsx
</span>{" "}
and add the following.
</p>
<CodeBlock code={server} />
<p>Alternatively, you can use a Client Component.</p>
<CodeBlock code={client} />
</TutorialStep>
<TutorialStep title="Build in a weekend and scale to millions!">
<p>You're ready to launch your product to the world! 🚀</p>
</TutorialStep>
</ol>
);
}

View File

@@ -0,0 +1,88 @@
import Link from "next/link";
import { TutorialStep } from "./tutorial-step";
import { ArrowUpRight } from "lucide-react";
export default function SignUpUserSteps() {
return (
<ol className="flex flex-col gap-6">
{process.env.VERCEL_ENV === "preview" ||
process.env.VERCEL_ENV === "production" ? (
<TutorialStep title="Set up redirect urls">
<p>It looks like this App is hosted on Vercel.</p>
<p className="mt-4">
This particular deployment is
<span className="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-xs font-medium text-secondary-foreground border">
"{process.env.VERCEL_ENV}"
</span>{" "}
on
<span className="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-xs font-medium text-secondary-foreground border">
https://{process.env.VERCEL_URL}
</span>
.
</p>
<p className="mt-4">
You will need to{" "}
<Link
className="text-primary hover:text-foreground"
href={
"https://supabase.com/dashboard/project/_/auth/url-configuration"
}
>
update your Supabase project
</Link>{" "}
with redirect URLs based on your Vercel deployment URLs.
</p>
<ul className="mt-4">
<li>
-{" "}
<span className="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-xs font-medium text-secondary-foreground border">
http://localhost:3000/**
</span>
</li>
<li>
-{" "}
<span className="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-xs font-medium text-secondary-foreground border">
{`https://${process.env.VERCEL_PROJECT_PRODUCTION_URL}/**`}
</span>
</li>
<li>
-{" "}
<span className="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-xs font-medium text-secondary-foreground border">
{`https://${process.env.VERCEL_PROJECT_PRODUCTION_URL?.replace(".vercel.app", "")}-*-[vercel-team-url].vercel.app/**`}
</span>{" "}
(Vercel Team URL can be found in{" "}
<Link
className="text-primary hover:text-foreground"
href="https://vercel.com/docs/accounts/create-a-team#find-your-team-id"
target="_blank"
>
Vercel Team settings
</Link>
)
</li>
</ul>
<Link
href="https://supabase.com/docs/guides/auth/redirect-urls#vercel-preview-urls"
target="_blank"
className="text-primary/50 hover:text-primary flex items-center text-sm gap-1 mt-4"
>
Redirect URLs Docs <ArrowUpRight size={14} />
</Link>
</TutorialStep>
) : null}
<TutorialStep title="Sign up your first user">
<p>
Head over to the{" "}
<Link
href="/sign-up"
className="font-bold hover:underline text-foreground/80"
>
Sign up
</Link>{" "}
page and sign up your first user. It's okay if this is just you for
now. Your awesome idea will have plenty of users later!
</p>
</TutorialStep>
</ol>
);
}

View File

@@ -0,0 +1,30 @@
import { Checkbox } from "../ui/checkbox";
export function TutorialStep({
title,
children,
}: {
title: string;
children: React.ReactNode;
}) {
return (
<li className="relative">
<Checkbox
id={title}
name={title}
className={`absolute top-[3px] mr-2 peer`}
/>
<label
htmlFor={title}
className={`relative text-base text-foreground peer-checked:line-through font-medium`}
>
<span className="ml-8">{title}</span>
<div
className={`ml-8 text-sm peer-checked:line-through font-normal text-muted-foreground`}
>
{children}
</div>
</label>
</li>
);
}