Skip to content

Commit c606420

Browse files
committed
feat: update to Next 13.3
1 parent 03ef292 commit c606420

File tree

124 files changed

+4738
-4038
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

124 files changed

+4738
-4038
lines changed

.eslintrc.json

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,17 @@
1515
},
1616
"settings": {
1717
"tailwindcss": {
18-
"callees": ["cn"]
18+
"callees": ["cn"],
19+
"config": "tailwind.config.js"
1920
},
2021
"next": {
2122
"rootDir": true
2223
}
23-
}
24+
},
25+
"overrides": [
26+
{
27+
"files": ["*.ts", "*.tsx"],
28+
"parser": "@typescript-eslint/parser"
29+
}
30+
]
2431
}

README.md

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,18 @@ An open source application built using the new router, server components and eve
66
> This app is a work in progress. I'm building this in public. You can follow the progress on Twitter [@shadcn](https://twitter.com/shadcn).
77
> See the roadmap below.
88
9-
## Demo
10-
11-
![screenshot-2](https://user-images.githubusercontent.com/124599/198038921-2b16b18b-cb4d-44b1-bd1d-6419d4a8d92c.png)
12-
139
## About this project
1410

15-
Right now, I'm using this project as an experiment to see how a modern app (with features like authentication, subscriptions, API routes, static pages for docs ...etc) would work in Next.js 13 and server components.
11+
This project as an experiment to see how a modern app (with features like authentication, subscriptions, API routes, static pages for docs ...etc) would work in Next.js 13 and server components.
1612

17-
I'll be posting updates and issues here.
13+
**This is not a starter template.**
1814

1915
A few people have asked me to turn this into a starter. I think we could do that once the new features are out of beta.
2016

2117
## Note on Performance
2218

2319
> **Warning**
24-
> This app is using the canary releases for Next.js 13 and React 18. The new router and app dir is still in beta and not production-ready.
25-
> NextAuth.js, which is used for authentication, is also not fully supported in Next.js 13 and RSC.
20+
> This app is using the unstable releases for Next.js 13 and React 18. The new router and app dir is still in beta and not production-ready.
2621
> **Expect some performance hits when testing the dashboard**.
2722
> If you see something broken, you can ping me [@shadcn](https://twitter.com/shadcn).
2823
@@ -32,6 +27,8 @@ A few people have asked me to turn this into a starter. I think we could do that
3227
- Routing, Layouts, Nested Layouts and Layout Groups
3328
- Data Fetching, Caching and Mutation
3429
- Loading UI
30+
- Route handlers
31+
- Metadata files
3532
- Server and Client Components
3633
- API Routes and Middlewares
3734
- Authentication using **NextAuth.js**
@@ -51,8 +48,7 @@ A few people have asked me to turn this into a starter. I think we could do that
5148
- [x] ~Subscriptions using Stripe~
5249
- [x] ~Responsive styles~
5350
- [x] ~Add OG image for blog using @vercel/og~
54-
- [ ] Add tests
55-
- [ ] Dark mode
51+
- [x] Dark mode
5652

5753
## Known Issues
5854

@@ -61,6 +57,7 @@ A list of things not working right now:
6157
1. ~GitHub authentication (use email)~
6258
2. ~[Prisma: Error: ENOENT: no such file or directory, open '/var/task/.next/server/chunks/schema.prisma'](https://github.com/prisma/prisma/issues/16117)~
6359
3. ~[Next.js 13: Client side navigation does not update head](https://github.com/vercel/next.js/issues/42414)~
60+
4. [Cannot use opengraph-image.tsx inside catch-all routes](https://github.com/vercel/next.js/issues/48162)
6461

6562
## Why not tRPC, Turborepo or X?
6663

app/(auth)/login/page.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import { Metadata } from "next"
22
import Link from "next/link"
33

44
import { cn } from "@/lib/utils"
5-
import { Icons } from "@/components/icons"
65
import { buttonVariants } from "@/components/ui/button"
6+
import { Icons } from "@/components/icons"
77
import { UserAuthForm } from "@/components/user-auth-form"
88

99
export const metadata: Metadata = {
@@ -18,7 +18,7 @@ export default function LoginPage() {
1818
href="/"
1919
className={cn(
2020
buttonVariants({ variant: "ghost" }),
21-
"absolute top-4 left-4 md:top-8 md:left-8"
21+
"absolute left-4 top-4 md:left-8 md:top-8"
2222
)}
2323
>
2424
<>
@@ -32,12 +32,12 @@ export default function LoginPage() {
3232
<h1 className="text-2xl font-semibold tracking-tight">
3333
Welcome back
3434
</h1>
35-
<p className="text-sm text-slate-500 dark:text-slate-400">
35+
<p className="text-sm text-muted-foreground">
3636
Enter your email to sign in to your account
3737
</p>
3838
</div>
3939
<UserAuthForm />
40-
<p className="px-8 text-center text-sm text-slate-500 dark:text-slate-400">
40+
<p className="px-8 text-center text-sm text-muted-foreground">
4141
<Link
4242
href="/register"
4343
className="hover:text-brand underline underline-offset-4"

app/(auth)/register/page.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import Link from "next/link"
22

33
import { cn } from "@/lib/utils"
4-
import { Icons } from "@/components/icons"
54
import { buttonVariants } from "@/components/ui/button"
5+
import { Icons } from "@/components/icons"
66
import { UserAuthForm } from "@/components/user-auth-form"
77

88
export const metadata = {
@@ -17,25 +17,25 @@ export default function RegisterPage() {
1717
href="/login"
1818
className={cn(
1919
buttonVariants({ variant: "ghost" }),
20-
"absolute top-4 right-4 md:top-8 md:right-8"
20+
"absolute right-4 top-4 md:right-8 md:top-8"
2121
)}
2222
>
2323
Login
2424
</Link>
25-
<div className="hidden h-full bg-slate-100 lg:block" />
25+
<div className="hidden h-full bg-muted lg:block" />
2626
<div className="lg:p-8">
2727
<div className="mx-auto flex w-full flex-col justify-center space-y-6 sm:w-[350px]">
2828
<div className="flex flex-col space-y-2 text-center">
2929
<Icons.logo className="mx-auto h-6 w-6" />
3030
<h1 className="text-2xl font-semibold tracking-tight">
3131
Create an account
3232
</h1>
33-
<p className="text-sm text-slate-500 dark:text-slate-400">
33+
<p className="text-sm text-muted-foreground">
3434
Enter your email below to create your account
3535
</p>
3636
</div>
3737
<UserAuthForm />
38-
<p className="px-8 text-center text-sm text-slate-500 dark:text-slate-400">
38+
<p className="px-8 text-center text-sm text-muted-foreground">
3939
By clicking continue, you agree to our{" "}
4040
<Link
4141
href="/terms"

app/(dashboard)/dashboard/billing/loading.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
import { CardSkeleton } from "@/components/card-skeleton"
12
import { DashboardHeader } from "@/components/header"
23
import { DashboardShell } from "@/components/shell"
3-
import { Card } from "@/components/ui/card"
44

55
export default function DashboardBillingLoading() {
66
return (
@@ -10,8 +10,7 @@ export default function DashboardBillingLoading() {
1010
text="Manage billing and your subscription plan."
1111
/>
1212
<div className="grid gap-10">
13-
<Card.Skeleton />
14-
<Card.Skeleton />
13+
<CardSkeleton />
1514
</div>
1615
</DashboardShell>
1716
)

app/(dashboard)/dashboard/billing/page.tsx

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,18 @@ import { authOptions } from "@/lib/auth"
44
import { getCurrentUser } from "@/lib/session"
55
import { stripe } from "@/lib/stripe"
66
import { getUserSubscriptionPlan } from "@/lib/subscription"
7+
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
8+
import {
9+
Card,
10+
CardContent,
11+
CardDescription,
12+
CardHeader,
13+
CardTitle,
14+
} from "@/components/ui/card"
715
import { BillingForm } from "@/components/billing-form"
816
import { DashboardHeader } from "@/components/header"
17+
import { Icons } from "@/components/icons"
918
import { DashboardShell } from "@/components/shell"
10-
import { Card } from "@/components/ui/card"
1119

1220
export const metadata = {
1321
title: "Billing",
@@ -38,38 +46,30 @@ export default async function BillingPage() {
3846
heading="Billing"
3947
text="Manage billing and your subscription plan."
4048
/>
41-
<div className="grid gap-10">
49+
<div className="grid gap-8">
50+
<Alert className="!pl-14">
51+
<Icons.warning />
52+
<AlertTitle>This is a demo app.</AlertTitle>
53+
<AlertDescription>
54+
Taxonomy app is a demo app using a Stripe test environment. You can
55+
find a list of test card numbers on the{" "}
56+
<a
57+
href="https://stripe.com/docs/testing#cards"
58+
target="_blank"
59+
rel="noreferrer"
60+
className="font-medium underline underline-offset-8"
61+
>
62+
Stripe docs
63+
</a>
64+
.
65+
</AlertDescription>
66+
</Alert>
4267
<BillingForm
4368
subscriptionPlan={{
4469
...subscriptionPlan,
4570
isCanceled,
4671
}}
4772
/>
48-
<Card>
49-
<Card.Header>
50-
<Card.Title>Note</Card.Title>
51-
</Card.Header>
52-
<Card.Content className="space-y-4 pb-6 text-sm">
53-
<p>
54-
Taxonomy app is a demo app using a Stripe test environment.{" "}
55-
<strong>
56-
You can test the upgrade and won&apos;t be charged.
57-
</strong>
58-
</p>
59-
<p>
60-
You can find a list of test card numbers on the{" "}
61-
<a
62-
href="https://stripe.com/docs/testing#cards"
63-
target="_blank"
64-
rel="noreferrer"
65-
className="font-medium underline underline-offset-8"
66-
>
67-
Stripe docs
68-
</a>
69-
.
70-
</p>
71-
</Card.Content>
72-
</Card>
7373
</div>
7474
</DashboardShell>
7575
)

app/(dashboard)/dashboard/layout.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { dashboardConfig } from "@/config/dashboard"
44
import { getCurrentUser } from "@/lib/session"
55
import { MainNav } from "@/components/main-nav"
66
import { DashboardNav } from "@/components/nav"
7+
import { SiteFooter } from "@/components/site-footer"
78
import { UserAccountNav } from "@/components/user-account-nav"
89

910
interface DashboardLayoutProps {
@@ -20,9 +21,9 @@ export default async function DashboardLayout({
2021
}
2122

2223
return (
23-
<div className="mx-auto flex flex-col space-y-6">
24-
<header className="container sticky top-0 z-40 bg-white">
25-
<div className="flex h-16 items-center justify-between border-b border-b-slate-200 py-4">
24+
<div className="flex min-h-screen flex-col space-y-6">
25+
<header className="sticky top-0 z-40 border-b bg-background">
26+
<div className="container flex h-16 items-center justify-between py-4">
2627
<MainNav items={dashboardConfig.mainNav} />
2728
<UserAccountNav
2829
user={{
@@ -33,14 +34,15 @@ export default async function DashboardLayout({
3334
/>
3435
</div>
3536
</header>
36-
<div className="container grid gap-12 md:grid-cols-[200px_1fr]">
37+
<div className="container grid flex-1 gap-12 md:grid-cols-[200px_1fr]">
3738
<aside className="hidden w-[200px] flex-col md:flex">
3839
<DashboardNav items={dashboardConfig.sidebarNav} />
3940
</aside>
4041
<main className="flex w-full flex-1 flex-col overflow-hidden">
4142
{children}
4243
</main>
4344
</div>
45+
<SiteFooter className="border-t" />
4446
</div>
4547
)
4648
}

app/(dashboard)/dashboard/loading.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export default function DashboardLoading() {
99
<DashboardHeader heading="Posts" text="Create and manage posts.">
1010
<PostCreateButton />
1111
</DashboardHeader>
12-
<div className="divide-y divide-neutral-200 rounded-md border border-slate-200">
12+
<div className="divide-border-200 divide-y rounded-md border">
1313
<PostItem.Skeleton />
1414
<PostItem.Skeleton />
1515
<PostItem.Skeleton />

app/(dashboard)/dashboard/page.tsx

Lines changed: 11 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,28 @@
1-
import { cache } from "react"
21
import { redirect } from "next/navigation"
3-
import { User } from "@prisma/client"
42

53
import { authOptions } from "@/lib/auth"
64
import { db } from "@/lib/db"
75
import { getCurrentUser } from "@/lib/session"
8-
import { cn } from "@/lib/utils"
96
import { EmptyPlaceholder } from "@/components/empty-placeholder"
107
import { DashboardHeader } from "@/components/header"
118
import { PostCreateButton } from "@/components/post-create-button"
129
import { PostItem } from "@/components/post-item"
1310
import { DashboardShell } from "@/components/shell"
14-
import { buttonVariants } from "@/components/ui/button"
1511

1612
export const metadata = {
1713
title: "Dashboard",
1814
}
1915

20-
const getPostsForUser = cache(async (userId: User["id"]) => {
21-
return await db.post.findMany({
16+
export default async function DashboardPage() {
17+
const user = await getCurrentUser()
18+
19+
if (!user) {
20+
redirect(authOptions?.pages?.signIn || "/login")
21+
}
22+
23+
const posts = await db.post.findMany({
2224
where: {
23-
authorId: userId,
25+
authorId: user.id,
2426
},
2527
select: {
2628
id: true,
@@ -32,16 +34,6 @@ const getPostsForUser = cache(async (userId: User["id"]) => {
3234
updatedAt: "desc",
3335
},
3436
})
35-
})
36-
37-
export default async function DashboardPage() {
38-
const user = await getCurrentUser()
39-
40-
if (!user) {
41-
redirect(authOptions?.pages?.signIn || "/login")
42-
}
43-
44-
const posts = await getPostsForUser(user.id)
4537

4638
return (
4739
<DashboardShell>
@@ -50,7 +42,7 @@ export default async function DashboardPage() {
5042
</DashboardHeader>
5143
<div>
5244
{posts?.length ? (
53-
<div className="divide-y divide-neutral-200 rounded-md border border-slate-200">
45+
<div className="divide-y divide-border rounded-md border">
5446
{posts.map((post) => (
5547
<PostItem key={post.id} post={post} />
5648
))}
@@ -62,12 +54,7 @@ export default async function DashboardPage() {
6254
<EmptyPlaceholder.Description>
6355
You don&apos;t have any posts yet. Start creating content.
6456
</EmptyPlaceholder.Description>
65-
<PostCreateButton
66-
className={cn(
67-
buttonVariants({ variant: "outline" }),
68-
"text-slate-900"
69-
)}
70-
/>
57+
<PostCreateButton variant="outline" />
7158
</EmptyPlaceholder>
7259
)}
7360
</div>

app/(dashboard)/dashboard/settings/loading.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
import { Card } from "@/components/ui/card"
2+
import { CardSkeleton } from "@/components/card-skeleton"
13
import { DashboardHeader } from "@/components/header"
24
import { DashboardShell } from "@/components/shell"
3-
import { Card } from "@/components/ui/card"
45

56
export default function DashboardSettingsLoading() {
67
return (
@@ -10,8 +11,7 @@ export default function DashboardSettingsLoading() {
1011
text="Manage account and website settings."
1112
/>
1213
<div className="grid gap-10">
13-
<Card.Skeleton />
14-
<Card.Skeleton />
14+
<CardSkeleton />
1515
</div>
1616
</DashboardShell>
1717
)

0 commit comments

Comments
 (0)