upstream #1
@ -1,5 +1,3 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import Link from '@/components/Link'
|
import Link from '@/components/Link'
|
||||||
// import { PageSEO } from '@/components/SEO'
|
// import { PageSEO } from '@/components/SEO'
|
||||||
import Tag from '@/components/Tag'
|
import Tag from '@/components/Tag'
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import { MDXLayoutRenderer } from 'pliny/mdx-components'
|
|
||||||
import { MDXComponents } from '@/components/MDXComponents'
|
|
||||||
|
|
||||||
const DEFAULT_LAYOUT = 'AuthorLayout'
|
|
||||||
|
|
||||||
export default function About({ author }) {
|
|
||||||
return (
|
|
||||||
<MDXLayoutRenderer
|
|
||||||
layout={author.layout || DEFAULT_LAYOUT}
|
|
||||||
content={author}
|
|
||||||
MDXComponents={MDXComponents}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,7 +1,17 @@
|
|||||||
import { allAuthors } from 'contentlayer/generated'
|
import { Authors, allAuthors } from 'contentlayer/generated'
|
||||||
import About from './About'
|
import { Mdx } from '@/components/MDXComponents'
|
||||||
|
import AuthorLayout from '@/layouts/AuthorLayout'
|
||||||
|
import { coreContent } from 'pliny/utils/contentlayer'
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
const author = allAuthors.find((p) => p.slug === 'default')
|
const author = allAuthors.find((p) => p.slug === 'default') as Authors
|
||||||
return <About author={author} />
|
const mainContent = coreContent(author)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<AuthorLayout content={mainContent}>
|
||||||
|
<Mdx code={author.body.code} />
|
||||||
|
</AuthorLayout>
|
||||||
|
</>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import { MDXLayoutRenderer } from 'pliny/mdx-components'
|
|
||||||
import { MDXComponents } from '@/components/MDXComponents'
|
|
||||||
import type { Blog } from 'contentlayer/generated'
|
|
||||||
|
|
||||||
const DEFAULT_LAYOUT = 'PostLayout'
|
|
||||||
|
|
||||||
export default function Blog({ post, authorDetails, prev, next }) {
|
|
||||||
return (
|
|
||||||
<MDXLayoutRenderer
|
|
||||||
layout={post.layout || DEFAULT_LAYOUT}
|
|
||||||
content={post}
|
|
||||||
MDXComponents={MDXComponents}
|
|
||||||
toc={post.toc}
|
|
||||||
authorDetails={authorDetails}
|
|
||||||
prev={prev}
|
|
||||||
next={next}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,8 +1,9 @@
|
|||||||
import PageTitle from '@/components/PageTitle'
|
import PageTitle from '@/components/PageTitle'
|
||||||
|
import { Mdx } from '@/components/MDXComponents'
|
||||||
import { sortedBlogPost, coreContent } from 'pliny/utils/contentlayer'
|
import { sortedBlogPost, coreContent } from 'pliny/utils/contentlayer'
|
||||||
import { allBlogs, allAuthors } from 'contentlayer/generated'
|
import { allBlogs, allAuthors } from 'contentlayer/generated'
|
||||||
import type { Authors, Blog } from 'contentlayer/generated'
|
import type { Authors, Blog } from 'contentlayer/generated'
|
||||||
import BlogPage from './Blog'
|
import PostLayout from '@/layouts/PostLayout'
|
||||||
|
|
||||||
export const generateStaticParams = async () => {
|
export const generateStaticParams = async () => {
|
||||||
const paths = allBlogs.map((p) => ({ slug: p.slug.split('/') }))
|
const paths = allBlogs.map((p) => ({ slug: p.slug.split('/') }))
|
||||||
@ -10,20 +11,19 @@ export const generateStaticParams = async () => {
|
|||||||
return paths
|
return paths
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Page({ params }: { params: { slug: string[] } }) {
|
export default async function Page({ params }: { params: { slug: string[] } }) {
|
||||||
const slug = params.slug.join('/')
|
const slug = params.slug.join('/')
|
||||||
const sortedPosts = sortedBlogPost(allBlogs) as Blog[]
|
const sortedPosts = sortedBlogPost(allBlogs) as Blog[]
|
||||||
const postIndex = sortedPosts.findIndex((p) => p.slug === slug)
|
const postIndex = sortedPosts.findIndex((p) => p.slug === slug)
|
||||||
const prevContent = sortedPosts[postIndex + 1] || null
|
const prev = coreContent(sortedPosts[postIndex + 1])
|
||||||
const prev = prevContent ? coreContent(prevContent) : null
|
const next = coreContent(sortedPosts[postIndex - 1])
|
||||||
const nextContent = sortedPosts[postIndex - 1] || null
|
const post = sortedPosts.find((p) => p.slug === slug) as Blog
|
||||||
const next = nextContent ? coreContent(nextContent) : null
|
|
||||||
const post = sortedPosts.find((p) => p.slug === slug)
|
|
||||||
const authorList = post?.authors || ['default']
|
const authorList = post?.authors || ['default']
|
||||||
const authorDetails = authorList.map((author) => {
|
const authorDetails = authorList.map((author) => {
|
||||||
const authorResults = allAuthors.find((p) => p.slug === author)
|
const authorResults = allAuthors.find((p) => p.slug === author)
|
||||||
return coreContent(authorResults as Authors)
|
return coreContent(authorResults as Authors)
|
||||||
})
|
})
|
||||||
|
const mainContent = coreContent(post)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -37,7 +37,9 @@ export default function Page({ params }: { params: { slug: string[] } }) {
|
|||||||
</PageTitle>
|
</PageTitle>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<BlogPage post={post} authorDetails={authorDetails} prev={prev} next={next} />
|
<PostLayout content={mainContent} authorDetails={authorDetails} next={next} prev={prev}>
|
||||||
|
<Mdx code={post.body.code} toc={post.toc} />
|
||||||
|
</PostLayout>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import siteMetadata from '@/data/siteMetadata'
|
|
||||||
import projectsData from '@/data/projectsData'
|
import projectsData from '@/data/projectsData'
|
||||||
import Card from '@/components/Card'
|
import Card from '@/components/Card'
|
||||||
|
|
||||||
|
7
components/BlogNewsletterForm.tsx
Normal file
7
components/BlogNewsletterForm.tsx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
// dot notation breaks RSC - https://github.com/vercel/next.js/issues/51593
|
||||||
|
// temporarily workaround to re-export
|
||||||
|
import { BlogNewsletterForm } from 'pliny/ui/NewsletterForm'
|
||||||
|
|
||||||
|
export default BlogNewsletterForm
|
13
components/ClientComponent.tsx
Normal file
13
components/ClientComponent.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { useState } from 'react'
|
||||||
|
|
||||||
|
export default function ClientComponent() {
|
||||||
|
const [count, setCount] = useState(0)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h1>Client Component</h1>
|
||||||
|
<p>Count: {count}</p>
|
||||||
|
<button onClick={() => setCount(count + 1)}>Inc</button>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
@ -2,7 +2,7 @@
|
|||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { AnchorHTMLAttributes, DetailedHTMLProps } from 'react'
|
import { AnchorHTMLAttributes, DetailedHTMLProps } from 'react'
|
||||||
|
|
||||||
const CustomLink = ({
|
const CustomLink = async ({
|
||||||
href,
|
href,
|
||||||
...rest
|
...rest
|
||||||
}: DetailedHTMLProps<AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>) => {
|
}: DetailedHTMLProps<AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>) => {
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
/* eslint-disable react/display-name */
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { MDXLayout, ComponentMap } from 'pliny/mdx-components'
|
import { useMDXComponent } from 'next-contentlayer/hooks'
|
||||||
|
import { ComponentMap } from 'pliny/mdx-components'
|
||||||
import { TOCInline } from 'pliny/ui/TOCInline'
|
import { TOCInline } from 'pliny/ui/TOCInline'
|
||||||
import { Pre } from 'pliny/ui/Pre'
|
import Pre from './Pre'
|
||||||
import { BlogNewsletterForm } from 'pliny/ui/NewsletterForm'
|
import BlogNewsletterForm from './BlogNewsletterForm'
|
||||||
|
// import { BlogNewsletterForm } from 'pliny/ui/NewsletterForm'
|
||||||
|
|
||||||
import Image from './Image'
|
import Image from './Image'
|
||||||
import CustomLink from './Link'
|
import CustomLink from './Link'
|
||||||
|
|
||||||
export const Wrapper = ({ layout, content, ...rest }: MDXLayout) => {
|
interface MdxProps {
|
||||||
const Layout = require(`../layouts/${layout}`).default
|
code: string
|
||||||
return <Layout content={content} {...rest} />
|
[key: string]: any
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MDXComponents: ComponentMap = {
|
export const MDXComponents: ComponentMap = {
|
||||||
@ -18,6 +19,11 @@ export const MDXComponents: ComponentMap = {
|
|||||||
TOCInline,
|
TOCInline,
|
||||||
a: CustomLink,
|
a: CustomLink,
|
||||||
pre: Pre,
|
pre: Pre,
|
||||||
wrapper: Wrapper,
|
|
||||||
BlogNewsletterForm,
|
BlogNewsletterForm,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function Mdx({ code, ...rest }: MdxProps) {
|
||||||
|
const Component = useMDXComponent(code)
|
||||||
|
|
||||||
|
return <Component components={{ ...MDXComponents }} {...rest} />
|
||||||
|
}
|
||||||
|
72
components/Pre.tsx
Normal file
72
components/Pre.tsx
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
'use client'
|
||||||
|
import { useState, useRef, ReactNode } from 'react'
|
||||||
|
|
||||||
|
const Pre = ({ children }: { children: ReactNode }) => {
|
||||||
|
const textInput = useRef(null)
|
||||||
|
const [hovered, setHovered] = useState(false)
|
||||||
|
const [copied, setCopied] = useState(false)
|
||||||
|
|
||||||
|
const onEnter = () => {
|
||||||
|
setHovered(true)
|
||||||
|
}
|
||||||
|
const onExit = () => {
|
||||||
|
setHovered(false)
|
||||||
|
setCopied(false)
|
||||||
|
}
|
||||||
|
const onCopy = () => {
|
||||||
|
setCopied(true)
|
||||||
|
// @ts-ignore
|
||||||
|
navigator.clipboard.writeText(textInput.current.textContent)
|
||||||
|
setTimeout(() => {
|
||||||
|
setCopied(false)
|
||||||
|
}, 2000)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div ref={textInput} onMouseEnter={onEnter} onMouseLeave={onExit} className="relative">
|
||||||
|
{hovered && (
|
||||||
|
<button
|
||||||
|
aria-label="Copy code"
|
||||||
|
className={`absolute right-2 top-2 h-8 w-8 rounded border-2 bg-gray-700 p-1 dark:bg-gray-800 ${
|
||||||
|
copied
|
||||||
|
? 'border-green-400 focus:border-green-400 focus:outline-none'
|
||||||
|
: 'border-gray-300'
|
||||||
|
}`}
|
||||||
|
onClick={onCopy}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke="currentColor"
|
||||||
|
fill="none"
|
||||||
|
className={copied ? 'text-green-400' : 'text-gray-300'}
|
||||||
|
>
|
||||||
|
{copied ? (
|
||||||
|
<>
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth={2}
|
||||||
|
d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth={2}
|
||||||
|
d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<pre>{children}</pre>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Pre
|
@ -1,3 +1,5 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
import siteMetadata from '@/data/siteMetadata'
|
import siteMetadata from '@/data/siteMetadata'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ import SectionContainer from '@/components/SectionContainer'
|
|||||||
import Image from '@/components/Image'
|
import Image from '@/components/Image'
|
||||||
import Tag from '@/components/Tag'
|
import Tag from '@/components/Tag'
|
||||||
import siteMetadata from '@/data/siteMetadata'
|
import siteMetadata from '@/data/siteMetadata'
|
||||||
import ScrollTopAndComment from '@/components/ScrollTopAndComment'
|
// import ScrollTopAndComment from '@/components/ScrollTopAndComment'
|
||||||
|
|
||||||
const editUrl = (path) => `${siteMetadata.siteRepo}/blob/master/data/${path}`
|
const editUrl = (path) => `${siteMetadata.siteRepo}/blob/master/data/${path}`
|
||||||
const discussUrl = (path) =>
|
const discussUrl = (path) =>
|
||||||
@ -33,12 +33,12 @@ interface LayoutProps {
|
|||||||
export default function PostLayout({ content, authorDetails, next, prev, children }: LayoutProps) {
|
export default function PostLayout({ content, authorDetails, next, prev, children }: LayoutProps) {
|
||||||
const { filePath, path, slug, date, title, tags } = content
|
const { filePath, path, slug, date, title, tags } = content
|
||||||
const basePath = path.split('/')[0]
|
const basePath = path.split('/')[0]
|
||||||
const [loadComments, setLoadComments] = useState(false)
|
// const [loadComments, setLoadComments] = useState(false)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContainer>
|
<SectionContainer>
|
||||||
{/* <BlogSEO url={`${siteMetadata.siteUrl}/${path}`} authorDetails={authorDetails} {...content} /> */}
|
{/* <BlogSEO url={`${siteMetadata.siteUrl}/${path}`} authorDetails={authorDetails} {...content} /> */}
|
||||||
<ScrollTopAndComment />
|
{/* <ScrollTopAndComment /> */}
|
||||||
<article>
|
<article>
|
||||||
<div className="xl:divide-y xl:divide-gray-200 xl:dark:divide-gray-700">
|
<div className="xl:divide-y xl:divide-gray-200 xl:dark:divide-gray-700">
|
||||||
<header className="pt-6 xl:pb-6">
|
<header className="pt-6 xl:pb-6">
|
||||||
@ -108,10 +108,10 @@ export default function PostLayout({ content, authorDetails, next, prev, childre
|
|||||||
className="pb-6 pt-6 text-center text-gray-700 dark:text-gray-300"
|
className="pb-6 pt-6 text-center text-gray-700 dark:text-gray-300"
|
||||||
id="comment"
|
id="comment"
|
||||||
>
|
>
|
||||||
{!loadComments && (
|
{/* {!loadComments && (
|
||||||
<button onClick={() => setLoadComments(true)}>Load Comments</button>
|
<button onClick={() => setLoadComments(true)}>Load Comments</button>
|
||||||
)}
|
)}
|
||||||
{loadComments && <Comments commentsConfig={siteMetadata.comments} slug={slug} />}
|
{loadComments && <Comments commentsConfig={siteMetadata.comments} slug={slug} />} */}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,89 +1,89 @@
|
|||||||
import { useState, ReactNode } from 'react'
|
// import { useState, ReactNode } from 'react'
|
||||||
import { Comments } from 'pliny/comments'
|
// import { Comments } from 'pliny/comments'
|
||||||
import { formatDate } from 'pliny/utils/formatDate'
|
// import { formatDate } from 'pliny/utils/formatDate'
|
||||||
import { CoreContent } from 'pliny/utils/contentlayer'
|
// import { CoreContent } from 'pliny/utils/contentlayer'
|
||||||
import type { Blog } from 'contentlayer/generated'
|
// import type { Blog } from 'contentlayer/generated'
|
||||||
import Link from '@/components/Link'
|
// import Link from '@/components/Link'
|
||||||
import PageTitle from '@/components/PageTitle'
|
// import PageTitle from '@/components/PageTitle'
|
||||||
import SectionContainer from '@/components/SectionContainer'
|
// import SectionContainer from '@/components/SectionContainer'
|
||||||
// import { BlogSEO } from '@/components/SEO'
|
// // import { BlogSEO } from '@/components/SEO'
|
||||||
import siteMetadata from '@/data/siteMetadata'
|
// import siteMetadata from '@/data/siteMetadata'
|
||||||
import ScrollTopAndComment from '@/components/ScrollTopAndComment'
|
// import ScrollTopAndComment from '@/components/ScrollTopAndComment'
|
||||||
|
|
||||||
interface LayoutProps {
|
// interface LayoutProps {
|
||||||
content: CoreContent<Blog>
|
// content: CoreContent<Blog>
|
||||||
children: ReactNode
|
// children: ReactNode
|
||||||
next?: { path: string; title: string }
|
// next?: { path: string; title: string }
|
||||||
prev?: { path: string; title: string }
|
// prev?: { path: string; title: string }
|
||||||
}
|
// }
|
||||||
|
|
||||||
export default function PostLayout({ content, next, prev, children }: LayoutProps) {
|
// export default function PostLayout({ content, next, prev, children }: LayoutProps) {
|
||||||
const [loadComments, setLoadComments] = useState(false)
|
// const [loadComments, setLoadComments] = useState(false)
|
||||||
|
|
||||||
const { path, slug, date, title } = content
|
// const { path, slug, date, title } = content
|
||||||
|
|
||||||
return (
|
// return (
|
||||||
<SectionContainer>
|
// <SectionContainer>
|
||||||
{/* <BlogSEO url={`${siteMetadata.siteUrl}/${path}`} {...content} /> */}
|
// {/* <BlogSEO url={`${siteMetadata.siteUrl}/${path}`} {...content} /> */}
|
||||||
<ScrollTopAndComment />
|
// <ScrollTopAndComment />
|
||||||
<article>
|
// <article>
|
||||||
<div>
|
// <div>
|
||||||
<header>
|
// <header>
|
||||||
<div className="space-y-1 border-b border-gray-200 pb-10 text-center dark:border-gray-700">
|
// <div className="space-y-1 border-b border-gray-200 pb-10 text-center dark:border-gray-700">
|
||||||
<dl>
|
// <dl>
|
||||||
<div>
|
// <div>
|
||||||
<dt className="sr-only">Published on</dt>
|
// <dt className="sr-only">Published on</dt>
|
||||||
<dd className="text-base font-medium leading-6 text-gray-500 dark:text-gray-400">
|
// <dd className="text-base font-medium leading-6 text-gray-500 dark:text-gray-400">
|
||||||
<time dateTime={date}>{formatDate(date, siteMetadata.locale)}</time>
|
// <time dateTime={date}>{formatDate(date, siteMetadata.locale)}</time>
|
||||||
</dd>
|
// </dd>
|
||||||
</div>
|
// </div>
|
||||||
</dl>
|
// </dl>
|
||||||
<div>
|
// <div>
|
||||||
<PageTitle>{title}</PageTitle>
|
// <PageTitle>{title}</PageTitle>
|
||||||
</div>
|
// </div>
|
||||||
</div>
|
// </div>
|
||||||
</header>
|
// </header>
|
||||||
<div className="grid-rows-[auto_1fr] divide-y divide-gray-200 pb-8 dark:divide-gray-700 xl:divide-y-0">
|
// <div className="grid-rows-[auto_1fr] divide-y divide-gray-200 pb-8 dark:divide-gray-700 xl:divide-y-0">
|
||||||
<div className="divide-y divide-gray-200 dark:divide-gray-700 xl:col-span-3 xl:row-span-2 xl:pb-0">
|
// <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-dark">{children}</div>
|
// <div className="prose max-w-none pb-8 pt-10 dark:prose-dark">{children}</div>
|
||||||
</div>
|
// </div>
|
||||||
{siteMetadata.comments && (
|
// {siteMetadata.comments && (
|
||||||
<div className="pb-6 pt-6 text-center text-gray-700 dark:text-gray-300" id="comment">
|
// <div className="pb-6 pt-6 text-center text-gray-700 dark:text-gray-300" id="comment">
|
||||||
{!loadComments && (
|
// {!loadComments && (
|
||||||
<button onClick={() => setLoadComments(true)}>Load Comments</button>
|
// <button onClick={() => setLoadComments(true)}>Load Comments</button>
|
||||||
)}
|
// )}
|
||||||
{loadComments && <Comments commentsConfig={siteMetadata.comments} slug={slug} />}
|
// {loadComments && <Comments commentsConfig={siteMetadata.comments} slug={slug} />}
|
||||||
</div>
|
// </div>
|
||||||
)}
|
// )}
|
||||||
<footer>
|
// <footer>
|
||||||
<div className="flex flex-col text-sm font-medium sm:flex-row sm:justify-between sm:text-base">
|
// <div className="flex flex-col text-sm font-medium sm:flex-row sm:justify-between sm:text-base">
|
||||||
{prev && (
|
// {prev && (
|
||||||
<div className="pt-4 xl:pt-8">
|
// <div className="pt-4 xl:pt-8">
|
||||||
<Link
|
// <Link
|
||||||
href={`/${prev.path}`}
|
// href={`/${prev.path}`}
|
||||||
className="text-primary-500 hover:text-primary-600 dark:hover:text-primary-400"
|
// className="text-primary-500 hover:text-primary-600 dark:hover:text-primary-400"
|
||||||
aria-label={`Previous post: ${prev.title}`}
|
// aria-label={`Previous post: ${prev.title}`}
|
||||||
>
|
// >
|
||||||
← {prev.title}
|
// ← {prev.title}
|
||||||
</Link>
|
// </Link>
|
||||||
</div>
|
// </div>
|
||||||
)}
|
// )}
|
||||||
{next && (
|
// {next && (
|
||||||
<div className="pt-4 xl:pt-8">
|
// <div className="pt-4 xl:pt-8">
|
||||||
<Link
|
// <Link
|
||||||
href={`/${next.path}`}
|
// href={`/${next.path}`}
|
||||||
className="text-primary-500 hover:text-primary-600 dark:hover:text-primary-400"
|
// className="text-primary-500 hover:text-primary-600 dark:hover:text-primary-400"
|
||||||
aria-label={`Next post: ${next.title}`}
|
// aria-label={`Next post: ${next.title}`}
|
||||||
>
|
// >
|
||||||
{next.title} →
|
// {next.title} →
|
||||||
</Link>
|
// </Link>
|
||||||
</div>
|
// </div>
|
||||||
)}
|
// )}
|
||||||
</div>
|
// </div>
|
||||||
</footer>
|
// </footer>
|
||||||
</div>
|
// </div>
|
||||||
</div>
|
// </div>
|
||||||
</article>
|
// </article>
|
||||||
</SectionContainer>
|
// </SectionContainer>
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
|
1
next-env.d.ts
vendored
1
next-env.d.ts
vendored
@ -1,6 +1,5 @@
|
|||||||
/// <reference types="next" />
|
/// <reference types="next" />
|
||||||
/// <reference types="next/image-types/global" />
|
/// <reference types="next/image-types/global" />
|
||||||
/// <reference types="next/navigation-types/compat/navigation" />
|
|
||||||
|
|
||||||
// NOTE: This file should not be edited
|
// NOTE: This file should not be edited
|
||||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user