Skip to content

Utility functions #23

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/[...slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export async function generateStaticParams(): Promise<PageProps["params"][]> {

export default async function PagePage({ params }: PageProps) {
const page = await getPageFromParams(params)


if (!page) {
notFound()
Expand Down
22 changes: 11 additions & 11 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
import Link from "next/link"
import "./globals.css"
import { Inter } from "next/font/google"
import { ThemeProvider } from "@/components/theme-provider"
import { Analytics } from "@/components/analytics"
import { ModeToggle } from "@/components/mode-toggle"
import Link from "next/link";
import "./globals.css";
import { Inter } from "next/font/google";
import { ThemeProvider } from "@/components/theme-provider";
import { Analytics } from "@/components/analytics";
import { ModeToggle } from "@/components/mode-toggle";

const inter = Inter({ subsets: ["latin"] })
const inter = Inter({ subsets: ["latin"] });

export const metadata = {
title: "Create Next App",
description: "Generated by create next app",
}
};

interface RootLayoutProps {
children: React.ReactNode
children: React.ReactNode;
}

export default function RootLayout({ children }: RootLayoutProps) {
return (
<html lang="en">
<body
className={`antialiased min-h-screen bg-white dark:bg-slate-950 text-slate-900 dark:text-slate-50 ${inter.className}`}
className={`antialiased overflow-x-hidden overflow-y-auto w-screen min-h-screen bg-white dark:bg-slate-950 text-slate-900 dark:text-slate-50 ${inter.className}`}
>
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
<div className="max-w-2xl mx-auto py-10 px-4">
Expand All @@ -39,5 +39,5 @@ export default function RootLayout({ children }: RootLayoutProps) {
</ThemeProvider>
</body>
</html>
)
);
}
2 changes: 1 addition & 1 deletion app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Link from "next/link"

export default function Home() {
return (
<div className="prose dark:prose-invert">
<div className="prose dark:prose-invert ">
{allPosts.map((post) => (
<article key={post._id}>
<Link href={post.slug}>
Expand Down
107 changes: 81 additions & 26 deletions app/posts/[...slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,64 +1,119 @@
import { notFound } from "next/navigation"
import { allPosts } from "contentlayer/generated"
import { notFound } from "next/navigation";
import { allPosts, allAuthors } from "contentlayer/generated";

import { Metadata } from "next"
import { Mdx } from "@/components/mdx-components"
import { Metadata } from "next";
import { Mdx } from "@/components/mdx-components";
import Image from "next/image";
import Link from "next/link";
import { formatDate } from "@/lib/utils";

interface PostProps {
params: {
slug: string[]
}
slug: string[];
};
}

async function getPostFromParams(params: PostProps["params"]) {
const slug = params?.slug?.join("/")
const post = allPosts.find((post) => post.slugAsParams === slug)
const slug = params?.slug?.join("/");
const post = allPosts.find((post) => post.slugAsParams === slug);

if (!post) {
null
null;
}

return post
return post;
}

export async function generateMetadata({
params,
}: PostProps): Promise<Metadata> {
const post = await getPostFromParams(params)
const post = await getPostFromParams(params);

if (!post) {
return {}
return {};
}

return {
title: post.title,
description: post.description,
}
};
}

export async function generateStaticParams(): Promise<PostProps["params"][]> {
return allPosts.map((post) => ({
slug: post.slugAsParams.split("/"),
}))
}));
}

export default async function PostPage({ params }: PostProps) {
const post = await getPostFromParams(params)
const post = await getPostFromParams(params);
const authors = post!.authors.map((author) =>
allAuthors.find(({ slug }) => slug === `/authors/${author}`)
);

if (!post) {
notFound()
notFound();
}

return (
<article className="py-6 prose dark:prose-invert">
<h1 className="mb-2">{post.title}</h1>
{post.description && (
<p className="text-xl mt-0 text-slate-700 dark:text-slate-200">
{post.description}
</p>
)}
<div className="container font-heading2 relative max-w-4xl py-6 gap-2">
<article className="py-6 prose dark:prose-invert overflow-x-hidden">
<h1 className="mb-2">{post.title}</h1>

{post.description && (
<p className="text-xl mt-0 text-slate-700 dark:text-slate-200">
{post.description}
</p>
)}
{post.date && (
<time
dateTime={post.date}
className="block text-sm text-gray-300/80 mx-auto"
>
{formatDate(post.date)}
</time>
)}

<hr className="my-4" />

<Mdx code={post.body.code} />
</article>
<hr className="my-4" />
<Mdx code={post.body.code} />
</article>
)
<p className="text-center mb-2">Published by</p>
{authors?.length ? (
<div className="mt-0 flex space-x-1 flex-col justify-center items-center gap-0">
{authors.map((author) =>
author ? (
<div
key={author._id}
className="flex flex-col gap-2 justify-center items-center"
>
<Link
key={author._id}
href={`https://twitter.com/${author.twitter}`}
className="flex items-center space-x-2 text-sm"
>
<Image
src={author.avatar!}
alt={author.name!}
width={42}
height={42}
className="rounded-full bg-white"
/>
<br />
<div className=" text-left leading-tight">
<p className="font-medium underline-none">{author.name}</p>
<p className="text-[12px] text-muted-foreground">
@{author.twitter}
</p>
</div>
</Link>
<p className="text-gray-300/80">{author.description}</p>
</div>
) : null
)}
</div>
) : null}
</div>
);
}
6 changes: 6 additions & 0 deletions content/authors/shadcn.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
name: Shadcn
avatar: /avatars/shadcn.png
twitter: shadcn
description: OSS contributor
---
2 changes: 2 additions & 0 deletions content/posts/deploying-next-apps.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
title: Deploying Next.js Apps
description: How to deploy your Next.js apps on Vercel.
date: "2023-01-02"
authors:
- shadcn
---

Until now, trying to style an article, document, or blog post with Tailwind has been a tedious task that required a keen eye for typography and a lot of complex custom CSS.
Expand Down
2 changes: 2 additions & 0 deletions content/posts/dynamic-routing-static-regeneration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
title: Dynamic Routing and Static Regeneration
description: How to use incremental static regeneration using dynamic routes.
date: "2023-03-04"
authors:
- shadcn
---

Until now, trying to style an article, document, or blog post with Tailwind has been a tedious task that required a keen eye for typography and a lot of complex custom CSS.
Expand Down
2 changes: 2 additions & 0 deletions content/posts/preview-mode-headless-cms.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
title: Preview Mode for Headless CMS
description: How to implement preview mode in your headless CMS.
date: "2023-04-09"
authors:
- shadcn
---

Until now, trying to style an article, document, or blog post with Tailwind has been a tedious task that required a keen eye for typography and a lot of complex custom CSS.
Expand Down
2 changes: 2 additions & 0 deletions content/posts/server-client-components.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
title: Server and Client Components
description: React Server Components allow developers to build applications that span the server and client.
date: "2023-01-08"
authors:
- shadcn
---

Until now, trying to style an article, document, or blog post with Tailwind has been a tedious task that required a keen eye for typography and a lot of complex custom CSS.
Expand Down
43 changes: 37 additions & 6 deletions contentlayer.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { defineDocumentType, makeSource } from "contentlayer/source-files"
import { defineDocumentType, makeSource } from "contentlayer/source-files";
import { title } from "process";

/** @type {import('contentlayer/source-files').ComputedFields} */
const computedFields = {
Expand All @@ -10,7 +11,7 @@ const computedFields = {
type: "string",
resolve: (doc) => doc._raw.flattenedPath.split("/").slice(1).join("/"),
},
}
};

export const Page = defineDocumentType(() => ({
name: "Page",
Expand All @@ -26,8 +27,32 @@ export const Page = defineDocumentType(() => ({
},
},
computedFields,
}))
}));

export const Author = defineDocumentType(() => ({
name: "Author",
filePathPattern: `authors/**/*.mdx`,
contentType: "mdx",
fields: {
name: {
type: "string",
require: true,
},
description: {
type: "string",
require: true,
},
avatar: {
type: "string",
require: true,
},
twitter: {
type: "string",
require: true,
},
},
computedFields,
}));
export const Post = defineDocumentType(() => ({
name: "Post",
filePathPattern: `posts/**/*.mdx`,
Expand All @@ -44,11 +69,17 @@ export const Post = defineDocumentType(() => ({
type: "date",
required: true,
},
authors: {
type: "list",
of: { type: "string" },
required: true,
},

},
computedFields,
}))
}));

export default makeSource({
contentDirPath: "./content",
documentTypes: [Post, Page],
})
documentTypes: [Post, Page , Author],
});
70 changes: 70 additions & 0 deletions lib/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { ClassValue, clsx } from "clsx"
import { twMerge } from "tailwind-merge"
import {format} from 'date-fns'
import { Metadata } from "next"

export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}

export function formatDate(input: string | number): string {
const date = new Date(input)
return date.toLocaleDateString("en-US", {
month: "long",
day: "numeric",
year: "numeric",
})
}

export function absoluteUrl(path: string) {
return `${process.env.NEXT_PUBLIC_APP_URL as string}${path}`
}

export function ReverseString(str : string) {
return str.split('').reverse().join('')
}
export function timeFormat(date : Date) {

const d = new Date(date);

const result = format(d, 'dd/MM/yyyy');
return result
}



export function constructMetadata({
title = "Nextjs MDX Starter",
description = "A Nextjs - MDX with contentlayer starter ",
// this will used for constructing an og stuff from your normal or catch all page
image = `${process.env.BASE_URL}/og.png`,
}: {
title?: string;
description?: string;
image?: string;
}): Metadata {
return {
title,
description,
openGraph: {
title,
description,
images: [
{
url: image,
},
],
},
twitter: {
card: "summary_large_image",
title,
description,
images: [image],
creator: '@shadcn',
},
icons: "/favicon.ico",
metadataBase: new URL(`${process.env.BASE_URL}`),
themeColor: "#000",
};
}

Loading