Skip to content

Commit

Permalink
Added TableOfContents feature
Browse files Browse the repository at this point in the history
  • Loading branch information
go-hoon committed Mar 2, 2024
1 parent 953c71a commit 4ec6700
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 51 deletions.
2 changes: 1 addition & 1 deletion app/blog/[...slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export default async function Page({ params }: { params: { slug: string[] } }) {
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
<Layout content={mainContent} authorDetails={authorDetails} next={next} prev={prev}>
<Layout content={mainContent} next={next} prev={prev}>
<MDXLayoutRenderer code={post.body.code} components={components} toc={post.toc} />
</Layout>
</>
Expand Down
30 changes: 30 additions & 0 deletions components/TableOfConents.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react'
import { Toc } from 'pliny/mdx-plugins'
import { TocItem } from 'pliny/mdx-plugins/remark-toc-headings'

interface Props {
toc: Toc
depthLevel?: number
}

export default function TableOfContents({ toc, depthLevel = 2 }: Props) {
const lowestDepth = toc.reduce((acc, item) => (item.depth < acc ? item.depth : acc), 6)
const filteredToc = toc.filter((item) => item.depth <= lowestDepth + depthLevel - 1)

return (
<ul className="text-sm">
{filteredToc.map((item: TocItem) => (
<li key={item.url}>
<a
key={item.url}
href={item.url}
className="block p-2 hover:text-primary-500 hover:underline"
style={{ paddingLeft: `${item.depth - lowestDepth}rem` }}
>
{item.value}
</a>
</li>
))}
</ul>
)
}
2 changes: 1 addition & 1 deletion contentlayer.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const computedFields: ComputedFields = {
type: 'string',
resolve: (doc) => doc._raw.sourceFilePath,
},
toc: { type: 'string', resolve: (doc) => extractTocHeadings(doc.body.raw) },
toc: { type: 'nested', resolve: (doc) => extractTocHeadings(doc.body.raw) },
}

/**
Expand Down
4 changes: 2 additions & 2 deletions data/blog/release-of-tailwind-nextjs-starter-blog-v2.0.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Welcome to the release of Tailwind Nextjs Starter Blog template v2.0. This relea

<TOCInline toc={props.toc} exclude="Introduction" />

## V1 to V2
### V1 to V2

![Github Traffic](/static/images/github-traffic.png)

Expand Down Expand Up @@ -127,7 +127,7 @@ Changes in the configuration file gets propagated to the components automaticall

Under the hood, Pliny exports high level components such as `<Analytics analyticsConfig={analyticsConfig}/>` and `<Comments commentsConfig={commentsConfig}/>` which takes in a configuration object and renders the appropriate component. Since the layouts are defined on the server side, Next.js is able to use the configuration object to determine which component to render and send only the required component bundle to the client.

## New Search Component
### New Search Component

What's a blog in 2023 without a command palette search bar?

Expand Down
61 changes: 14 additions & 47 deletions layouts/PostLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { ReactNode } from 'react'
import { CoreContent } from 'pliny/utils/contentlayer'
import type { Blog, Authors } from 'contentlayer/generated'
import type { Blog } from 'contentlayer/generated'
import Comments from '@/components/Comments'
import Link from '@/components/Link'
import PageTitle from '@/components/PageTitle'
import SectionContainer from '@/components/SectionContainer'
import Image from '@/components/Image'
import Tag from '@/components/Tag'
import siteMetadata from '@/data/siteMetadata'
import ScrollTopAndComment from '@/components/ScrollTopAndComment'
import TableOfContents from '@/components/TableOfConents'

const editUrl = (path) => `${siteMetadata.siteRepo}/blob/main/data/${path}`
const discussUrl = (path) =>
Expand All @@ -23,13 +23,12 @@ const postDateTemplate: Intl.DateTimeFormatOptions = {

interface LayoutProps {
content: CoreContent<Blog>
authorDetails: CoreContent<Authors>[]
next?: { path: string; title: string }
prev?: { path: string; title: string }
children: ReactNode
}

export default function PostLayout({ content, authorDetails, next, prev, children }: LayoutProps) {
export default function PostLayout({ content, next, prev, children }: LayoutProps) {
const { filePath, path, slug, date, title, tags } = content
const basePath = path.split('/')[0]

Expand All @@ -38,7 +37,7 @@ export default function PostLayout({ content, authorDetails, next, prev, childre
<ScrollTopAndComment />
<article>
<div className="xl:divide-y xl:divide-gray-200 xl:dark:divide-gray-700">
<header className="pt-6 xl:pb-6">
<header className="py-6">
<div className="space-y-1 text-center">
<dl className="space-y-10">
<div>
Expand All @@ -56,50 +55,18 @@ export default function PostLayout({ content, authorDetails, next, prev, childre
</div>
</header>
<div className="grid-rows-[auto_1fr] divide-y divide-gray-200 pb-8 dark:divide-gray-700 xl:grid xl:grid-cols-4 xl:gap-x-6 xl:divide-y-0">
<dl className="pb-10 pt-6 xl:border-b xl:border-gray-200 xl:pt-11 xl:dark:border-gray-700">
<dt className="sr-only">Authors</dt>
<dd>
<ul className="flex flex-wrap justify-center gap-4 sm:space-x-12 xl:block xl:space-x-0 xl:space-y-8">
{authorDetails.map((author) => (
<li className="flex items-center space-x-2" key={author.name}>
{author.avatar && (
<Image
src={author.avatar}
width={38}
height={38}
alt="avatar"
className="h-10 w-10 rounded-full"
/>
)}
<dl className="whitespace-nowrap text-sm font-medium leading-5">
<dt className="sr-only">Name</dt>
<dd className="text-gray-900 dark:text-gray-100">{author.name}</dd>
<dt className="sr-only">Twitter</dt>
<dd>
{author.twitter && (
<Link
href={author.twitter}
className="text-primary-500 hover:text-primary-600 dark:hover:text-primary-400"
>
{author.twitter.replace('https://twitter.com/', '@')}
</Link>
)}
</dd>
</dl>
</li>
))}
</ul>
</dd>
</dl>
<div>
{content.toc && content.toc.length != 0 && (
<div className="border-t pb-6 pt-6 xl:border-b xl:border-t-0 xl:border-gray-200 xl:pt-11 xl:dark:border-gray-700">
<h2 className="pb-2 text-xs font-medium uppercase leading-5 tracking-wide text-gray-500 dark:divide-gray-700 dark:text-gray-400">
Table of contents
</h2>
<TableOfContents toc={content.toc} />
</div>
)}
</div>
<div className="divide-y divide-gray-200 dark:divide-gray-700 xl:col-span-3 xl:row-span-2 xl:pb-0">
<div className="prose max-w-none pb-8 pt-10 dark:prose-invert">{children}</div>
<div className="pb-6 pt-6 text-sm text-gray-700 dark:text-gray-300">
<Link href={discussUrl(path)} rel="nofollow">
Discuss on Twitter
</Link>
{` • `}
<Link href={editUrl(filePath)}>View on GitHub</Link>
</div>
{siteMetadata.comments && (
<div
className="pb-6 pt-6 text-center text-gray-700 dark:text-gray-300"
Expand Down

0 comments on commit 4ec6700

Please sign in to comment.