Skip to content

Commit b4c95f7

Browse files
author
vlnabatov
committed
Initial commit
Created from https://vercel.com/new
0 parents  commit b4c95f7

33 files changed

+6169
-0
lines changed

Diff for: .eslintrc.json

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "next/core-web-vitals"
3+
}

Diff for: .gitignore

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
8+
# testing
9+
/coverage
10+
11+
# next.js
12+
/.next/
13+
/out/
14+
15+
# production
16+
/build
17+
18+
# misc
19+
.DS_Store
20+
*.pem
21+
22+
# debug
23+
npm-debug.log*
24+
yarn-debug.log*
25+
yarn-error.log*
26+
27+
# local env files
28+
.env*.local
29+
30+
# vercel
31+
.vercel
32+
33+
# typescript
34+
*.tsbuildinfo
35+
next-env.d.ts
36+
.contentlayer

Diff for: .vscode/settings.json

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"typescript.tsdk": "node_modules/.pnpm/[email protected]/node_modules/typescript/lib",
3+
"typescript.enablePromptUseWorkspaceTsdk": true
4+
}

Diff for: README.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Next.js + Contentlayer
2+
3+
A template with Next.js 13 app dir, Contentlayer, Tailwind CSS and dark mode.
4+
5+
https://next-contentlayer.vercel.app
6+
7+

Diff for: app/[...slug]/page.tsx

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { notFound } from "next/navigation"
2+
import { Metadata } from "next"
3+
import { allPages } from "contentlayer/generated"
4+
5+
import { Mdx } from "@/components/mdx-components"
6+
7+
interface PageProps {
8+
params: {
9+
slug: string[]
10+
}
11+
}
12+
13+
async function getPageFromParams(params: PageProps["params"]) {
14+
const slug = params?.slug?.join("/")
15+
const page = allPages.find((page) => page.slugAsParams === slug)
16+
17+
if (!page) {
18+
null
19+
}
20+
21+
return page
22+
}
23+
24+
export async function generateMetadata({
25+
params,
26+
}: PageProps): Promise<Metadata> {
27+
const page = await getPageFromParams(params)
28+
29+
if (!page) {
30+
return {}
31+
}
32+
33+
return {
34+
title: page.title,
35+
description: page.description,
36+
}
37+
}
38+
39+
export async function generateStaticParams(): Promise<PageProps["params"][]> {
40+
return allPages.map((page) => ({
41+
slug: page.slugAsParams.split("/"),
42+
}))
43+
}
44+
45+
export default async function PagePage({ params }: PageProps) {
46+
const page = await getPageFromParams(params)
47+
48+
if (!page) {
49+
notFound()
50+
}
51+
52+
return (
53+
<article className="py-6 prose dark:prose-invert">
54+
<h1>{page.title}</h1>
55+
{page.description && <p className="text-xl">{page.description}</p>}
56+
<hr />
57+
<Mdx code={page.body.code} />
58+
</article>
59+
)
60+
}

Diff for: app/api/hello/route.ts

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export async function GET(request: Request) {
2+
return new Response('Hello, Next.js!')
3+
}

Diff for: app/favicon.ico

25.3 KB
Binary file not shown.

Diff for: app/globals.css

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@tailwind base;
2+
@tailwind components;
3+
@tailwind utilities;

Diff for: app/layout.tsx

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import Link from "next/link"
2+
import "./globals.css"
3+
import { Inter } from "next/font/google"
4+
import { ThemeProvider } from "@/components/theme-provider"
5+
import { Analytics } from "@/components/analytics"
6+
import { ModeToggle } from "@/components/mode-toggle"
7+
8+
const inter = Inter({ subsets: ["latin"] })
9+
10+
export const metadata = {
11+
title: "Create Next App",
12+
description: "Generated by create next app",
13+
}
14+
15+
interface RootLayoutProps {
16+
children: React.ReactNode
17+
}
18+
19+
export default function RootLayout({ children }: RootLayoutProps) {
20+
return (
21+
<html lang="en">
22+
<body
23+
className={`antialiased min-h-screen bg-white dark:bg-slate-950 text-slate-900 dark:text-slate-50 ${inter.className}`}
24+
>
25+
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
26+
<div className="max-w-2xl mx-auto py-10 px-4">
27+
<header>
28+
<div className="flex items-center justify-between">
29+
<ModeToggle />
30+
<nav className="ml-auto text-sm font-medium space-x-6">
31+
<Link href="/">Home</Link>
32+
<Link href="/about">About</Link>
33+
</nav>
34+
</div>
35+
</header>
36+
<main>{children}</main>
37+
</div>
38+
<Analytics />
39+
</ThemeProvider>
40+
</body>
41+
</html>
42+
)
43+
}

Diff for: app/page.tsx

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { allPosts } from "@/.contentlayer/generated"
2+
import Link from "next/link"
3+
4+
export default function Home() {
5+
return (
6+
<div className="prose dark:prose-invert">
7+
{allPosts.map((post) => (
8+
<article key={post._id}>
9+
<Link href={post.slug}>
10+
<h2>{post.title}</h2>
11+
</Link>
12+
{post.description && <p>{post.description}</p>}
13+
</article>
14+
))}
15+
</div>
16+
)
17+
}

Diff for: app/posts/[...slug]/page.tsx

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { notFound } from "next/navigation"
2+
import { allPosts } from "contentlayer/generated"
3+
4+
import { Metadata } from "next"
5+
import { Mdx } from "@/components/mdx-components"
6+
7+
interface PostProps {
8+
params: {
9+
slug: string[]
10+
}
11+
}
12+
13+
async function getPostFromParams(params: PostProps["params"]) {
14+
const slug = params?.slug?.join("/")
15+
const post = allPosts.find((post) => post.slugAsParams === slug)
16+
17+
if (!post) {
18+
null
19+
}
20+
21+
return post
22+
}
23+
24+
export async function generateMetadata({
25+
params,
26+
}: PostProps): Promise<Metadata> {
27+
const post = await getPostFromParams(params)
28+
29+
if (!post) {
30+
return {}
31+
}
32+
33+
return {
34+
title: post.title,
35+
description: post.description,
36+
}
37+
}
38+
39+
export async function generateStaticParams(): Promise<PostProps["params"][]> {
40+
return allPosts.map((post) => ({
41+
slug: post.slugAsParams.split("/"),
42+
}))
43+
}
44+
45+
export default async function PostPage({ params }: PostProps) {
46+
const post = await getPostFromParams(params)
47+
48+
if (!post) {
49+
notFound()
50+
}
51+
52+
return (
53+
<article className="py-6 prose dark:prose-invert">
54+
<h1 className="mb-2">{post.title}</h1>
55+
{post.description && (
56+
<p className="text-xl mt-0 text-slate-700 dark:text-slate-200">
57+
{post.description}
58+
</p>
59+
)}
60+
<hr className="my-4" />
61+
<Mdx code={post.body.code} />
62+
</article>
63+
)
64+
}

Diff for: components/analytics.tsx

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
"use client"
2+
3+
import { Analytics as VercelAnalytics } from "@vercel/analytics/react"
4+
5+
export function Analytics() {
6+
return <VercelAnalytics />
7+
}

Diff for: components/mdx-components.tsx

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import Image from "next/image"
2+
import { useMDXComponent } from "next-contentlayer/hooks"
3+
4+
const components = {
5+
Image,
6+
}
7+
8+
interface MdxProps {
9+
code: string
10+
}
11+
12+
export function Mdx({ code }: MdxProps) {
13+
const Component = useMDXComponent(code)
14+
15+
return <Component components={components} />
16+
}

Diff for: components/mode-toggle.tsx

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
"use client"
2+
3+
import { useTheme } from "next-themes"
4+
5+
export function ModeToggle() {
6+
const { setTheme, theme } = useTheme()
7+
8+
return (
9+
<button
10+
onClick={() => setTheme(theme === "light" ? "dark" : "light")}
11+
className="border rounded-md w-6 h-6 flex items-center justify-center">
12+
<span className="sr-only">Toggle mode</span>
13+
{theme !== "dark" ? (
14+
<svg
15+
xmlns="http://www.w3.org/2000/svg"
16+
fill="none"
17+
viewBox="0 0 24 24"
18+
strokeWidth={1.5}
19+
stroke="currentColor"
20+
className="w-4 h-4">
21+
<path
22+
strokeLinecap="round"
23+
strokeLinejoin="round"
24+
d="M21.752 15.002A9.718 9.718 0 0118 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 003 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 009.002-5.998z"
25+
/>
26+
</svg>
27+
) : (
28+
<svg
29+
xmlns="http://www.w3.org/2000/svg"
30+
fill="none"
31+
viewBox="0 0 24 24"
32+
strokeWidth={1.5}
33+
stroke="currentColor"
34+
className="w-4 h-4">
35+
<path
36+
strokeLinecap="round"
37+
strokeLinejoin="round"
38+
d="M12 3v2.25m6.364.386l-1.591 1.591M21 12h-2.25m-.386 6.364l-1.591-1.591M12 18.75V21m-4.773-4.227l-1.591 1.591M5.25 12H3m4.227-4.773L5.636 5.636M15.75 12a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0z"
39+
/>
40+
</svg>
41+
)}
42+
</button>
43+
)
44+
}

Diff for: components/theme-provider.tsx

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
"use client"
2+
3+
import * as React from "react"
4+
import { ThemeProvider as NextThemesProvider } from "next-themes"
5+
import type { ThemeProviderProps } from "next-themes/dist/types"
6+
7+
export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
8+
return <NextThemesProvider {...props}>{children}</NextThemesProvider>
9+
}

Diff for: content/pages/about.mdx

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
title: About
3+
description: About the site
4+
---
5+
6+
Blandit libero volutpat sed cras ornare arcu. Cursus sit amet dictum sit amet. Nunc vel risus commodo viverra maecenas accumsan. Libero id faucibus nisl tincidunt eget nullam non nisi est. Varius quam quisque id diam vel quam. Id donec ultrices tincidunt arcu non.
7+
8+
## Consent
9+
10+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Volutpat sed cras ornare arcu. Nibh ipsum consequat nisl vel pretium lectus quam id leo. A arcu cursus vitae congue. Amet justo donec enim diam. Vel pharetra vel turpis nunc eget lorem. Gravida quis blandit turpis cursus in. Semper auctor neque vitae tempus. Elementum facilisis leo vel fringilla est ullamcorper eget nulla. Imperdiet nulla malesuada pellentesque elit eget.
11+
12+
Felis donec et odio pellentesque diam volutpat commodo sed.
13+
14+
Tortor consequat id porta nibh. Fames ac turpis egestas maecenas pharetra convallis posuere morbi leo. Scelerisque fermentum dui faucibus in. Tortor posuere ac ut consequat semper viverra.
15+
16+
## Information we collect
17+
18+
Amet justo donec enim diam. In hendrerit gravida rutrum quisque non. Hac habitasse platea dictumst quisque sagittis purus sit.
19+
20+
## How we use your Information
21+
22+
Ut sem nulla pharetra diam sit amet nisl suscipit adipiscing. Consectetur adipiscing elit pellentesque habitant. Ut tristique et egestas quis ipsum suspendisse ultrices gravida.

0 commit comments

Comments
 (0)