diff --git a/app/(auth)/register/page.tsx b/app/(auth)/register/page.tsx
index ef26445..bd5dcaf 100644
--- a/app/(auth)/register/page.tsx
+++ b/app/(auth)/register/page.tsx
@@ -1,14 +1,24 @@
import Link from "next/link"
+import { cn } from "@/lib/utils"
import { Icons } from "@/components/icons"
-import { UserAuthForm } from "@/components/dashboard/user-auth-form"
+import { buttonVariants } from "@/components/ui/button"
+import { UserAuthForm } from "@/components/user-auth-form"
+
+export const metadata = {
+ title: "Create an account",
+ description: "Create an account to get started.",
+}
export default function RegisterPage() {
return (
Login
@@ -17,19 +27,27 @@ export default function RegisterPage() {
-
Create an account
-
+
+ Create an account
+
+
Enter your email below to create your account
-
+
By clicking continue, you agree to our{" "}
-
+
Terms of Service
{" "}
and{" "}
-
+
Privacy Policy
.
diff --git a/app/(dashboard)/dashboard/billing/loading.tsx b/app/(dashboard)/dashboard/billing/loading.tsx
index 2019484..c1cde9c 100644
--- a/app/(dashboard)/dashboard/billing/loading.tsx
+++ b/app/(dashboard)/dashboard/billing/loading.tsx
@@ -1,6 +1,6 @@
-import { DashboardHeader } from "@/components/dashboard/header"
-import { DashboardShell } from "@/components/dashboard/shell"
-import { Card } from "@/ui/card"
+import { DashboardHeader } from "@/components/header"
+import { DashboardShell } from "@/components/shell"
+import { Card } from "@/components/ui/card"
export default function DashboardBillingLoading() {
return (
diff --git a/app/(dashboard)/dashboard/billing/page.tsx b/app/(dashboard)/dashboard/billing/page.tsx
index b701477..8630a15 100644
--- a/app/(dashboard)/dashboard/billing/page.tsx
+++ b/app/(dashboard)/dashboard/billing/page.tsx
@@ -1,26 +1,31 @@
import { redirect } from "next/navigation"
-import { getCurrentUser } from "@/lib/session"
import { authOptions } from "@/lib/auth"
+import { getCurrentUser } from "@/lib/session"
import { stripe } from "@/lib/stripe"
-import { getUserSubscriptionPlan as getUserSubscriptionPlan } from "@/lib/subscription"
-import { Card } from "@/ui/card"
-import { DashboardHeader } from "@/components/dashboard/header"
-import { DashboardShell } from "@/components/dashboard/shell"
-import { BillingForm } from "@/components/dashboard/billing-form"
+import { getUserSubscriptionPlan } from "@/lib/subscription"
+import { BillingForm } from "@/components/billing-form"
+import { DashboardHeader } from "@/components/header"
+import { DashboardShell } from "@/components/shell"
+import { Card } from "@/components/ui/card"
+
+export const metadata = {
+ title: "Billing",
+ description: "Manage billing and your subscription plan.",
+}
export default async function BillingPage() {
const user = await getCurrentUser()
if (!user) {
- redirect(authOptions.pages.signIn)
+ redirect(authOptions?.pages?.signIn || "/login")
}
const subscriptionPlan = await getUserSubscriptionPlan(user.id)
// If user has a pro plan, check cancel status on Stripe.
let isCanceled = false
- if (subscriptionPlan.isPro) {
+ if (subscriptionPlan.isPro && subscriptionPlan.stripeSubscriptionId) {
const stripePlan = await stripe.subscriptions.retrieve(
subscriptionPlan.stripeSubscriptionId
)
diff --git a/app/(dashboard)/dashboard/layout.tsx b/app/(dashboard)/dashboard/layout.tsx
index f4e08df..4893d10 100644
--- a/app/(dashboard)/dashboard/layout.tsx
+++ b/app/(dashboard)/dashboard/layout.tsx
@@ -2,9 +2,9 @@ import { notFound } from "next/navigation"
import { dashboardConfig } from "@/config/dashboard"
import { getCurrentUser } from "@/lib/session"
-import { DashboardNav } from "@/components/dashboard/nav"
-import { UserAccountNav } from "@/components/dashboard/user-account-nav"
import { MainNav } from "@/components/main-nav"
+import { DashboardNav } from "@/components/nav"
+import { UserAccountNav } from "@/components/user-account-nav"
interface DashboardLayoutProps {
children?: React.ReactNode
diff --git a/app/(dashboard)/dashboard/loading.tsx b/app/(dashboard)/dashboard/loading.tsx
index 02bc9f4..57f2969 100644
--- a/app/(dashboard)/dashboard/loading.tsx
+++ b/app/(dashboard)/dashboard/loading.tsx
@@ -1,7 +1,7 @@
-import { DashboardHeader } from "@/components/dashboard/header"
-import { DashboardShell } from "@/components/dashboard/shell"
-import { PostCreateButton } from "@/components/dashboard/post-create-button"
-import { PostItem } from "@/components/dashboard/post-item"
+import { DashboardHeader } from "@/components/header"
+import { PostCreateButton } from "@/components/post-create-button"
+import { PostItem } from "@/components/post-item"
+import { DashboardShell } from "@/components/shell"
export default function DashboardLoading() {
return (
diff --git a/app/(dashboard)/dashboard/page.tsx b/app/(dashboard)/dashboard/page.tsx
index 6551560..ef847e5 100644
--- a/app/(dashboard)/dashboard/page.tsx
+++ b/app/(dashboard)/dashboard/page.tsx
@@ -1,15 +1,21 @@
-import { redirect } from "next/navigation"
import { cache } from "react"
+import { redirect } from "next/navigation"
+import { User } from "@prisma/client"
+import { authOptions } from "@/lib/auth"
import { db } from "@/lib/db"
import { getCurrentUser } from "@/lib/session"
-import { User } from "@prisma/client"
-import { authOptions } from "@/lib/auth"
-import { DashboardHeader } from "@/components/dashboard/header"
-import { PostCreateButton } from "@/components/dashboard/post-create-button"
-import { DashboardShell } from "@/components/dashboard/shell"
-import { PostItem } from "@/components/dashboard/post-item"
-import { EmptyPlaceholder } from "@/components/dashboard/empty-placeholder"
+import { cn } from "@/lib/utils"
+import { EmptyPlaceholder } from "@/components/empty-placeholder"
+import { DashboardHeader } from "@/components/header"
+import { PostCreateButton } from "@/components/post-create-button"
+import { PostItem } from "@/components/post-item"
+import { DashboardShell } from "@/components/shell"
+import { buttonVariants } from "@/components/ui/button"
+
+export const metadata = {
+ title: "Dashboard",
+}
const getPostsForUser = cache(async (userId: User["id"]) => {
return await db.post.findMany({
@@ -32,7 +38,7 @@ export default async function DashboardPage() {
const user = await getCurrentUser()
if (!user) {
- redirect(authOptions.pages.signIn)
+ redirect(authOptions?.pages?.signIn || "/login")
}
const posts = await getPostsForUser(user.id)
@@ -56,7 +62,12 @@ export default async function DashboardPage() {
You don't have any posts yet. Start creating content.
-
+
)}
diff --git a/app/(dashboard)/dashboard/settings/loading.tsx b/app/(dashboard)/dashboard/settings/loading.tsx
index e213ea8..613a5f5 100644
--- a/app/(dashboard)/dashboard/settings/loading.tsx
+++ b/app/(dashboard)/dashboard/settings/loading.tsx
@@ -1,6 +1,6 @@
-import { DashboardHeader } from "@/components/dashboard/header"
-import { DashboardShell } from "@/components/dashboard/shell"
-import { Card } from "@/ui/card"
+import { DashboardHeader } from "@/components/header"
+import { DashboardShell } from "@/components/shell"
+import { Card } from "@/components/ui/card"
export default function DashboardSettingsLoading() {
return (
diff --git a/app/(dashboard)/dashboard/settings/page.tsx b/app/(dashboard)/dashboard/settings/page.tsx
index d997dff..6e8545d 100644
--- a/app/(dashboard)/dashboard/settings/page.tsx
+++ b/app/(dashboard)/dashboard/settings/page.tsx
@@ -1,16 +1,21 @@
import { redirect } from "next/navigation"
-import { getCurrentUser } from "@/lib/session"
import { authOptions } from "@/lib/auth"
-import { DashboardHeader } from "@/components/dashboard/header"
-import { DashboardShell } from "@/components/dashboard/shell"
-import { UserNameForm } from "@/components/dashboard/user-name-form"
+import { getCurrentUser } from "@/lib/session"
+import { DashboardHeader } from "@/components/header"
+import { DashboardShell } from "@/components/shell"
+import { UserNameForm } from "@/components/user-name-form"
+
+export const metadata = {
+ title: "Settings",
+ description: "Manage account and website settings.",
+}
export default async function SettingsPage() {
const user = await getCurrentUser()
if (!user) {
- redirect(authOptions.pages.signIn)
+ redirect(authOptions?.pages?.signIn || "/login")
}
return (
@@ -20,7 +25,9 @@ export default async function SettingsPage() {
text="Manage account and website settings."
/>
-
+ {user?.name ? (
+
+ ) : null}
)
diff --git a/app/(docs)/docs/[[...slug]]/head.tsx b/app/(docs)/docs/[[...slug]]/head.tsx
deleted file mode 100644
index 37cdf37..0000000
--- a/app/(docs)/docs/[[...slug]]/head.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import { allDocs } from "contentlayer/generated"
-
-import MdxHead from "@/components/docs/mdx-head"
-
-export default function Head({ params }) {
- const slug = params?.slug?.join("/") || ""
- const doc = allDocs.find((doc) => doc.slugAsParams === slug)
- return (
-
- )
-}
diff --git a/app/(docs)/docs/[[...slug]]/page.tsx b/app/(docs)/docs/[[...slug]]/page.tsx
index 9517e35..7e26ef6 100644
--- a/app/(docs)/docs/[[...slug]]/page.tsx
+++ b/app/(docs)/docs/[[...slug]]/page.tsx
@@ -2,11 +2,14 @@ import { notFound } from "next/navigation"
import { allDocs } from "contentlayer/generated"
import { getTableOfContents } from "@/lib/toc"
-import { Mdx } from "@/components/docs/mdx"
-import { DashboardTableOfContents } from "@/components/docs/toc"
-import { DocsPageHeader } from "@/components/docs/page-header"
-import { DocsPager } from "@/components/docs/pager"
+import { Mdx } from "@/components/mdx"
+import { DocsPageHeader } from "@/components/page-header"
+import { DocsPager } from "@/components/pager"
+import { DashboardTableOfContents } from "@/components/toc"
import "@/styles/mdx.css"
+import { Metadata } from "next"
+
+import { absoluteUrl } from "@/lib/utils"
interface DocPageProps {
params: {
@@ -14,6 +17,59 @@ interface DocPageProps {
}
}
+async function getDocFromParams(params) {
+ const slug = params.slug?.join("/") || ""
+ const doc = allDocs.find((doc) => doc.slugAsParams === slug)
+
+ if (!doc) {
+ null
+ }
+
+ return doc
+}
+
+export async function generateMetadata({
+ params,
+}: DocPageProps): Promise
{
+ const doc = await getDocFromParams(params)
+
+ if (!doc) {
+ return {}
+ }
+
+ const url = process.env.NEXT_PUBLIC_APP_URL
+
+ const ogUrl = new URL(`${url}/api/og`)
+ ogUrl.searchParams.set("heading", doc.description ?? doc.title)
+ ogUrl.searchParams.set("type", "Documentation")
+ ogUrl.searchParams.set("mode", "dark")
+
+ return {
+ title: doc.title,
+ description: doc.description,
+ openGraph: {
+ title: doc.title,
+ description: doc.description,
+ type: "article",
+ url: absoluteUrl(doc.slug),
+ images: [
+ {
+ url: ogUrl.toString(),
+ width: 1200,
+ height: 630,
+ alt: doc.title,
+ },
+ ],
+ },
+ twitter: {
+ card: "summary_large_image",
+ title: doc.title,
+ description: doc.description,
+ images: [ogUrl.toString()],
+ },
+ }
+}
+
export async function generateStaticParams(): Promise<
DocPageProps["params"][]
> {
@@ -23,8 +79,7 @@ export async function generateStaticParams(): Promise<
}
export default async function DocPage({ params }: DocPageProps) {
- const slug = params?.slug?.join("/") || ""
- const doc = allDocs.find((doc) => doc.slugAsParams === slug)
+ const doc = await getDocFromParams(params)
if (!doc) {
notFound()
diff --git a/app/(docs)/docs/layout.tsx b/app/(docs)/docs/layout.tsx
index 41fc042..2b08491 100644
--- a/app/(docs)/docs/layout.tsx
+++ b/app/(docs)/docs/layout.tsx
@@ -1,5 +1,5 @@
import { docsConfig } from "@/config/docs"
-import { DocsSidebarNav } from "@/components/docs/sidebar-nav"
+import { DocsSidebarNav } from "@/components/sidebar-nav"
interface DocsLayoutProps {
children: React.ReactNode
@@ -8,7 +8,7 @@ interface DocsLayoutProps {
export default function DocsLayout({ children }: DocsLayoutProps) {
return (
-
-
- Build your own
-
{posts?.length ? (
diff --git a/app/(marketing)/layout.tsx b/app/(marketing)/layout.tsx
index 5b0172f..7c8543c 100644
--- a/app/(marketing)/layout.tsx
+++ b/app/(marketing)/layout.tsx
@@ -1,8 +1,10 @@
import Link from "next/link"
import { marketingConfig } from "@/config/marketing"
+import { cn } from "@/lib/utils"
import { MainNav } from "@/components/main-nav"
import { SiteFooter } from "@/components/site-footer"
+import { buttonVariants } from "@/components/ui/button"
interface MarketingLayoutProps {
children: React.ReactNode
@@ -19,7 +21,7 @@ export default async function MarketingLayout({