chore: sync with v1.1.0
This commit is contained in:
parent
de3de08bbc
commit
16e4eaee28
|
@ -4,39 +4,95 @@ import siteMetadata from '@/data/siteMetadata'
|
|||
import { AuthorFrontMatter } from 'types/AuthorFrontMatter'
|
||||
import { PostFrontMatter } from 'types/PostFrontMatter'
|
||||
|
||||
interface PageSeoProps {
|
||||
interface CommonSEOProps {
|
||||
title: string
|
||||
description: string
|
||||
ogType: string
|
||||
ogImage:
|
||||
| string
|
||||
| {
|
||||
'@type': string
|
||||
url: string
|
||||
}[]
|
||||
twImage: string
|
||||
}
|
||||
|
||||
export const PageSeo = ({ title, description }: PageSeoProps) => {
|
||||
const CommonSEO = ({ title, description, ogType, ogImage, twImage }: CommonSEOProps) => {
|
||||
const router = useRouter()
|
||||
return (
|
||||
<Head>
|
||||
<title>{`${title}`}</title>
|
||||
<title>{title}</title>
|
||||
<meta name="robots" content="follow, index" />
|
||||
<meta name="description" content={description} />
|
||||
<meta property="og:url" content={`${siteMetadata.siteUrl}${router.asPath}`} />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:type" content={ogType} />
|
||||
<meta property="og:site_name" content={siteMetadata.title} />
|
||||
<meta property="og:description" content={description} />
|
||||
<meta property="og:title" content={title} />
|
||||
<meta property="og:image" content={`${siteMetadata.siteUrl}${siteMetadata.socialBanner}`} />
|
||||
{Array.isArray(ogImage) ? (
|
||||
ogImage.map(({ url }) => <meta property="og:image" content={url} key={url} />)
|
||||
) : (
|
||||
<meta property="og:image" content={ogImage} key={ogImage} />
|
||||
)}
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:site" content={siteMetadata.twitter} />
|
||||
<meta name="twitter:title" content={title} />
|
||||
<meta name="twitter:description" content={description} />
|
||||
<meta name="twitter:image" content={`${siteMetadata.siteUrl}${siteMetadata.socialBanner}`} />
|
||||
<meta name="twitter:image" content={twImage} />
|
||||
</Head>
|
||||
)
|
||||
}
|
||||
|
||||
interface PageSEOProps {
|
||||
title: string
|
||||
description: string
|
||||
}
|
||||
|
||||
export const PageSEO = ({ title, description }: PageSEOProps) => {
|
||||
const ogImageUrl = siteMetadata.siteUrl + siteMetadata.socialBanner
|
||||
const twImageUrl = siteMetadata.siteUrl + siteMetadata.socialBanner
|
||||
return (
|
||||
<CommonSEO
|
||||
title={title}
|
||||
description={description}
|
||||
ogType="website"
|
||||
ogImage={ogImageUrl}
|
||||
twImage={twImageUrl}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export const TagSEO = ({ title, description }: PageSEOProps) => {
|
||||
const ogImageUrl = siteMetadata.siteUrl + siteMetadata.socialBanner
|
||||
const twImageUrl = siteMetadata.siteUrl + siteMetadata.socialBanner
|
||||
const router = useRouter()
|
||||
return (
|
||||
<>
|
||||
<CommonSEO
|
||||
title={title}
|
||||
description={description}
|
||||
ogType="website"
|
||||
ogImage={ogImageUrl}
|
||||
twImage={twImageUrl}
|
||||
/>
|
||||
<Head>
|
||||
<link
|
||||
rel="alternate"
|
||||
type="application/rss+xml"
|
||||
title={`${description} - RSS feed`}
|
||||
href={`${siteMetadata.siteUrl}${router.asPath}/feed.xml`}
|
||||
/>
|
||||
</Head>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
interface BlogSeoProps extends PostFrontMatter {
|
||||
authorDetails?: AuthorFrontMatter[]
|
||||
url: string
|
||||
}
|
||||
|
||||
export const BlogSeo = ({
|
||||
export const BlogSEO = ({
|
||||
authorDetails,
|
||||
title,
|
||||
summary,
|
||||
|
@ -100,31 +156,26 @@ export const BlogSeo = ({
|
|||
description: summary,
|
||||
}
|
||||
|
||||
const twImageUrl = featuredImages[0].url
|
||||
|
||||
return (
|
||||
<>
|
||||
<CommonSEO
|
||||
title={title}
|
||||
description={summary}
|
||||
ogType="article"
|
||||
ogImage={featuredImages}
|
||||
twImage={twImageUrl}
|
||||
/>
|
||||
<Head>
|
||||
<title>{`${title}`}</title>
|
||||
<meta name="robots" content="follow, index" />
|
||||
<meta name="description" content={summary} />
|
||||
<meta property="og:url" content={`${siteMetadata.siteUrl}${router.asPath}`} />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:site_name" content={siteMetadata.title} />
|
||||
<meta property="og:description" content={summary} />
|
||||
<meta property="og:title" content={title} />
|
||||
{featuredImages.map((img) => (
|
||||
<meta property="og:image" content={img.url} key={img.url} />
|
||||
))}
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:site" content={siteMetadata.twitter} />
|
||||
<meta name="twitter:title" content={title} />
|
||||
<meta name="twitter:description" content={summary} />
|
||||
<meta name="twitter:image" content={featuredImages[0].url} />
|
||||
{date && <meta property="article:published_time" content={publishedAt} />}
|
||||
{lastmod && <meta property="article:modified_time" content={modifiedAt} />}
|
||||
<link rel="canonical" href={`${siteMetadata.siteUrl}${router.asPath}`} />
|
||||
<script
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(structuredData, null, 2) }}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: JSON.stringify(structuredData, null, 2),
|
||||
}}
|
||||
/>
|
||||
</Head>
|
||||
</>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import GA from './GoogleAnalytics'
|
||||
import Plausible from './Plausible'
|
||||
import SimpleAnalytics from './SimpleAnalytics'
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import SocialIcon from '@/components/social-icons'
|
||||
import Image from '@/components/Image'
|
||||
import { PageSeo } from '@/components/SEO'
|
||||
import { PageSEO } from '@/components/SEO'
|
||||
import { ReactNode } from 'react'
|
||||
import { AuthorFrontMatter } from 'types/AuthorFrontMatter'
|
||||
|
||||
|
@ -14,7 +14,7 @@ export default function AuthorLayout({ children, frontMatter }: Props) {
|
|||
|
||||
return (
|
||||
<>
|
||||
<PageSeo title={`About - ${name}`} description={`About me - ${name}`} />
|
||||
<PageSEO title={`About - ${name}`} description={`About me - ${name}`} />
|
||||
<div className="divide-y">
|
||||
<div className="pt-6 pb-8 space-y-2 md:space-y-5">
|
||||
<h1 className="text-3xl font-extrabold leading-9 tracking-tight text-gray-900 dark:text-gray-100 sm:text-4xl sm:leading-10 md:text-6xl md:leading-14">
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import Link from '@/components/Link'
|
||||
import PageTitle from '@/components/PageTitle'
|
||||
import SectionContainer from '@/components/SectionContainer'
|
||||
import { BlogSeo } from '@/components/SEO'
|
||||
import { BlogSEO } from '@/components/SEO'
|
||||
import Image from '@/components/Image'
|
||||
import Tag from '@/components/Tag'
|
||||
import siteMetadata from '@/data/siteMetadata'
|
||||
|
@ -36,7 +36,7 @@ export default function PostLayout({ frontMatter, authorDetails, next, prev, chi
|
|||
|
||||
return (
|
||||
<SectionContainer>
|
||||
<BlogSeo
|
||||
<BlogSEO
|
||||
url={`${siteMetadata.siteUrl}/blog/${slug}`}
|
||||
authorDetails={authorDetails}
|
||||
{...frontMatter}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import Link from '@/components/Link'
|
||||
import PageTitle from '@/components/PageTitle'
|
||||
import SectionContainer from '@/components/SectionContainer'
|
||||
import { BlogSeo } from '@/components/SEO'
|
||||
import { BlogSEO } from '@/components/SEO'
|
||||
import siteMetadata from '@/data/siteMetadata'
|
||||
import formatDate from '@/lib/utils/formatDate'
|
||||
import Comments from '@/components/comments'
|
||||
|
@ -20,7 +20,7 @@ export default function PostLayout({ frontMatter, next, prev, children }: Props)
|
|||
|
||||
return (
|
||||
<SectionContainer>
|
||||
<BlogSeo url={`${siteMetadata.siteUrl}/blog/${slug}`} {...frontMatter} />
|
||||
<BlogSEO url={`${siteMetadata.siteUrl}/blog/${slug}`} {...frontMatter} />
|
||||
<article>
|
||||
<div>
|
||||
<header>
|
||||
|
|
39
lib/mdx.ts
39
lib/mdx.ts
|
@ -1,17 +1,26 @@
|
|||
import { Node } from 'unist'
|
||||
import { bundleMDX } from 'mdx-bundler'
|
||||
import fs from 'fs'
|
||||
import matter from 'gray-matter'
|
||||
import path from 'path'
|
||||
import readingTime from 'reading-time'
|
||||
import visit from 'unist-util-visit'
|
||||
import codeTitles from './remark-code-title'
|
||||
import remarkTocHeadings from './remark-toc-headings'
|
||||
import imgToJsx from './img-to-jsx'
|
||||
import { visit } from 'unist-util-visit'
|
||||
import type { Pluggable } from 'unified'
|
||||
import getAllFilesRecursively from './utils/files'
|
||||
import { PostFrontMatter } from 'types/PostFrontMatter'
|
||||
import { AuthorFrontMatter } from 'types/AuthorFrontMatter'
|
||||
import { Toc } from 'types/Toc'
|
||||
// Remark packages
|
||||
import remarkSlug from 'remark-slug'
|
||||
import remarkAutolinkHeadings from 'remark-autolink-headings'
|
||||
import remarkGfm from 'remark-gfm'
|
||||
import remarkFootnotes from 'remark-footnotes'
|
||||
import remarkMath from 'remark-math'
|
||||
import remarkCodeTitles from './remark-code-title'
|
||||
import remarkTocHeadings from './remark-toc-headings'
|
||||
import remarkImgToJsx from './remark-img-to-jsx'
|
||||
// Rehype packages
|
||||
import rehypeKatex from 'rehype-katex'
|
||||
import rehypePrismPlus from 'rehype-prism-plus'
|
||||
|
||||
const root = process.cwd()
|
||||
|
||||
|
@ -82,22 +91,22 @@ export async function getFileBySlug<T>(type: 'authors' | 'blog', slug: string |
|
|||
// plugins in the future.
|
||||
options.remarkPlugins = [
|
||||
...(options.remarkPlugins ?? []),
|
||||
require('remark-slug'),
|
||||
require('remark-autolink-headings'),
|
||||
remarkSlug,
|
||||
remarkAutolinkHeadings,
|
||||
[remarkTocHeadings, { exportRef: toc }],
|
||||
require('remark-gfm'),
|
||||
codeTitles,
|
||||
[require('remark-footnotes'), { inlineNotes: true }],
|
||||
require('remark-math'),
|
||||
imgToJsx,
|
||||
remarkGfm,
|
||||
remarkCodeTitles,
|
||||
[remarkFootnotes, { inlineNotes: true }],
|
||||
remarkMath,
|
||||
remarkImgToJsx,
|
||||
]
|
||||
options.rehypePlugins = [
|
||||
...(options.rehypePlugins ?? []),
|
||||
require('rehype-katex'),
|
||||
[require('rehype-prism-plus'), { ignoreMissing: true }],
|
||||
rehypeKatex,
|
||||
[rehypePrismPlus, { ignoreMissing: true }] as Pluggable,
|
||||
() => {
|
||||
return (tree) => {
|
||||
visit<Node & { properties: { className: string[] } }>(tree, 'element', (node) => {
|
||||
visit(tree, 'element', (node) => {
|
||||
const [token, type] = node.properties.className || []
|
||||
if (token === 'token') {
|
||||
node.properties.className = [tokenClassNames[type]]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Parent } from 'unist'
|
||||
import visit from 'unist-util-visit'
|
||||
import { visit } from 'unist-util-visit'
|
||||
|
||||
export default function codeTitles() {
|
||||
export default function remarkCodeTitles() {
|
||||
return (tree: Parent & { lang?: string }) =>
|
||||
visit(tree, 'code', (node: Parent & { lang?: string }, index) => {
|
||||
const nodeLang = node.lang || ''
|
||||
|
|
|
@ -1,22 +1,23 @@
|
|||
import { Parent, Node, Literal } from 'unist'
|
||||
import visit from 'unist-util-visit'
|
||||
import { visit } from 'unist-util-visit'
|
||||
import sizeOf from 'image-size'
|
||||
import fs from 'fs'
|
||||
|
||||
export default function ImgToJsx() {
|
||||
type ImageNode = Parent & {
|
||||
url: string
|
||||
alt: string
|
||||
name: string
|
||||
attributes: (Literal & { name: string })[]
|
||||
}
|
||||
|
||||
export default function remarkImgToJsx() {
|
||||
return (tree: Node) => {
|
||||
visit<Node>(
|
||||
visit(
|
||||
tree,
|
||||
// only visit p tags that contain an img element
|
||||
(node: Parent): node is Parent =>
|
||||
node.type === 'paragraph' && node.children.some((n) => n.type === 'image'),
|
||||
(node: Parent) => {
|
||||
type ImageNode = Parent & {
|
||||
url: string
|
||||
alt: string
|
||||
name: string
|
||||
attributes: (Literal & { name: string })[]
|
||||
}
|
||||
const imageNode = node.children.find((n) => n.type === 'image') as ImageNode
|
||||
|
||||
// only local files
|
|
@ -1,13 +1,13 @@
|
|||
//@ts-nocheck
|
||||
import { Parent } from 'unist'
|
||||
import visit from 'unist-util-visit'
|
||||
import { visit } from 'unist-util-visit'
|
||||
|
||||
export default function (options) {
|
||||
export default function remarkTocHeadings(options) {
|
||||
return (tree: Parent) =>
|
||||
visit(tree, 'heading', (node, index, parent) => {
|
||||
visit(tree, 'heading', (node) => {
|
||||
options.exportRef.push({
|
||||
value: node.children[1].value,
|
||||
url: node.children[0].url,
|
||||
value: node.children[0].value || node.children[1].value,
|
||||
url: node.children[0].url || node.children[1].url,
|
||||
depth: node.depth,
|
||||
})
|
||||
})
|
||||
|
|
3
next-env.d.ts
vendored
3
next-env.d.ts
vendored
|
@ -1,3 +1,6 @@
|
|||
/// <reference types="next" />
|
||||
/// <reference types="next/types/global" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// @ts-check
|
||||
|
||||
const withBundleAnalyzer = require('@next/bundle-analyzer')({
|
||||
enabled: process.env.ANALYZE === 'true',
|
||||
})
|
||||
|
@ -13,6 +11,7 @@ module.exports = withBundleAnalyzer({
|
|||
eslint: {
|
||||
dirs: ['pages', 'components', 'lib', 'layouts', 'scripts'],
|
||||
},
|
||||
experimental: { esmExternals: true },
|
||||
webpack: (config, { dev, isServer }) => {
|
||||
config.module.rules.push({
|
||||
test: /\.(png|jpe?g|gif|mp4)$/i,
|
||||
|
|
2955
package-lock.json
generated
2955
package-lock.json
generated
File diff suppressed because it is too large
Load diff
32
package.json
32
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "tailwind-nextjs-starter-blog",
|
||||
"version": "v1.0.0",
|
||||
"version": "1.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "next-remote-watch ./data",
|
||||
|
@ -18,22 +18,24 @@
|
|||
"esbuild": "^0.12.15",
|
||||
"gray-matter": "^4.0.2",
|
||||
"image-size": "1.0.0",
|
||||
"mdx-bundler": "^5.1.2",
|
||||
"next": "11.0.1",
|
||||
"mdx-bundler": "^6.0.1",
|
||||
"next": "11.1.0",
|
||||
"next-themes": "^0.0.14",
|
||||
"postcss": "^8.3.5",
|
||||
"preact": "^10.5.13",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"reading-time": "1.3.0",
|
||||
"rehype-katex": "^5.0.0",
|
||||
"rehype-prism-plus": "0.0.2",
|
||||
"remark-autolink-headings": "6.0.1",
|
||||
"remark-footnotes": "^3.0.0",
|
||||
"remark-gfm": "^1.0.0",
|
||||
"remark-math": "^4.0.0",
|
||||
"remark-slug": "6.0.0",
|
||||
"tailwindcss": "^2.2.2"
|
||||
"rehype-katex": "^6.0.0",
|
||||
"rehype-prism-plus": "^0.0.5",
|
||||
"remark-autolink-headings": "^7.0.0",
|
||||
"remark-footnotes": "^4.0.0",
|
||||
"remark-gfm": "^2.0.0",
|
||||
"remark-math": "^5.0.0",
|
||||
"remark-slug": "^7.0.0",
|
||||
"sharp": "^0.28.3",
|
||||
"tailwindcss": "^2.2.2",
|
||||
"unist-util-visit": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next/bundle-analyzer": "11.0.1",
|
||||
|
@ -56,13 +58,7 @@
|
|||
"lint-staged": "^11.0.0",
|
||||
"next-remote-watch": "^1.0.0",
|
||||
"prettier": "2.2.1",
|
||||
"rehype": "11.0.0",
|
||||
"remark-frontmatter": "3.0.0",
|
||||
"remark-parse": "9.0.0",
|
||||
"remark-stringify": "9.0.1",
|
||||
"typescript": "^4.3.5",
|
||||
"unified": "9.2.1",
|
||||
"unist-util-visit": "2.0.3"
|
||||
"typescript": "^4.3.5"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.+(js|jsx|ts|tsx)": [
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { getAllFilesFrontMatter } from '@/lib/mdx'
|
||||
import siteMetadata from '@/data/siteMetadata'
|
||||
import ListLayout from '@/layouts/ListLayout'
|
||||
import { PageSeo } from '@/components/SEO'
|
||||
import { PageSEO } from '@/components/SEO'
|
||||
import { GetStaticProps, InferGetStaticPropsType } from 'next'
|
||||
import { ComponentProps } from 'react'
|
||||
|
||||
|
@ -29,7 +29,7 @@ export default function Blog({
|
|||
}: InferGetStaticPropsType<typeof getStaticProps>) {
|
||||
return (
|
||||
<>
|
||||
<PageSeo title={`Blog - ${siteMetadata.author}`} description={siteMetadata.description} />
|
||||
<PageSEO title={`Blog - ${siteMetadata.author}`} description={siteMetadata.description} />
|
||||
<ListLayout
|
||||
posts={posts}
|
||||
initialDisplayPosts={initialDisplayPosts}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { PageSeo } from '@/components/SEO'
|
||||
import { PageSEO } from '@/components/SEO'
|
||||
import siteMetadata from '@/data/siteMetadata'
|
||||
import { getAllFilesFrontMatter } from '@/lib/mdx'
|
||||
import ListLayout from '@/layouts/ListLayout'
|
||||
|
@ -54,7 +54,7 @@ export default function PostPage({
|
|||
}: InferGetStaticPropsType<typeof getStaticProps>) {
|
||||
return (
|
||||
<>
|
||||
<PageSeo title={siteMetadata.title} description={siteMetadata.description} />
|
||||
<PageSEO title={siteMetadata.title} description={siteMetadata.description} />
|
||||
<ListLayout
|
||||
posts={posts}
|
||||
initialDisplayPosts={initialDisplayPosts}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import Link from '@/components/Link'
|
||||
import { PageSeo } from '@/components/SEO'
|
||||
import { PageSEO } from '@/components/SEO'
|
||||
import Tag from '@/components/Tag'
|
||||
import siteMetadata from '@/data/siteMetadata'
|
||||
import { getAllFilesFrontMatter } from '@/lib/mdx'
|
||||
|
@ -18,7 +18,7 @@ export const getStaticProps: GetStaticProps<{ posts: PostFrontMatter[] }> = asyn
|
|||
export default function Home({ posts }: InferGetStaticPropsType<typeof getStaticProps>) {
|
||||
return (
|
||||
<>
|
||||
<PageSeo title={siteMetadata.title} description={siteMetadata.description} />
|
||||
<PageSEO title={siteMetadata.title} description={siteMetadata.description} />
|
||||
<div className="divide-y divide-gray-200 dark:divide-gray-700">
|
||||
<div className="pt-6 pb-8 space-y-2 md:space-y-5">
|
||||
<h1 className="text-3xl font-extrabold leading-9 tracking-tight text-gray-900 dark:text-gray-100 sm:text-4xl sm:leading-10 md:text-6xl md:leading-14">
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import siteMetadata from '@/data/siteMetadata'
|
||||
import projectsData from '@/data/projectsData'
|
||||
import Card from '@/components/Card'
|
||||
import { PageSeo } from '@/components/SEO'
|
||||
import { PageSEO } from '@/components/SEO'
|
||||
|
||||
export default function Projects() {
|
||||
return (
|
||||
<>
|
||||
<PageSeo title={`Projects - ${siteMetadata.author}`} description={siteMetadata.description} />
|
||||
<PageSEO title={`Projects - ${siteMetadata.author}`} description={siteMetadata.description} />
|
||||
<div className="divide-y divide-gray-200 dark:divide-gray-700">
|
||||
<div className="pt-6 pb-8 space-y-2 md:space-y-5">
|
||||
<h1 className="text-3xl font-extrabold leading-9 tracking-tight text-gray-900 dark:text-gray-100 sm:text-4xl sm:leading-10 md:text-6xl md:leading-14">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import Link from '@/components/Link'
|
||||
import { PageSeo } from '@/components/SEO'
|
||||
import { PageSEO } from '@/components/SEO'
|
||||
import Tag from '@/components/Tag'
|
||||
import siteMetadata from '@/data/siteMetadata'
|
||||
import { getAllTags } from '@/lib/tags'
|
||||
|
@ -16,7 +16,7 @@ export default function Tags({ tags }: InferGetStaticPropsType<typeof getStaticP
|
|||
const sortedTags = Object.keys(tags).sort((a, b) => tags[b] - tags[a])
|
||||
return (
|
||||
<>
|
||||
<PageSeo title={`Tags - ${siteMetadata.author}`} description="Things I blog about" />
|
||||
<PageSEO title={`Tags - ${siteMetadata.author}`} description="Things I blog about" />
|
||||
<div className="flex flex-col items-start justify-start divide-y divide-gray-200 dark:divide-gray-700 md:justify-center md:items-center md:divide-y-0 md:flex-row md:space-x-6 md:mt-24">
|
||||
<div className="pt-6 pb-8 space-x-2 md:space-y-5">
|
||||
<h1 className="text-3xl font-extrabold leading-9 tracking-tight text-gray-900 dark:text-gray-100 sm:text-4xl sm:leading-10 md:text-6xl md:leading-14 md:border-r-2 md:px-6">
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { PageSeo } from '@/components/SEO'
|
||||
import { TagSEO } from '@/components/SEO'
|
||||
import siteMetadata from '@/data/siteMetadata'
|
||||
import ListLayout from '@/layouts/ListLayout'
|
||||
import generateRss from '@/lib/generate-rss'
|
||||
|
@ -48,9 +48,9 @@ export default function Tag({ posts, tag }: InferGetStaticPropsType<typeof getSt
|
|||
const title = tag[0].toUpperCase() + tag.split(' ').join('-').slice(1)
|
||||
return (
|
||||
<>
|
||||
<PageSeo
|
||||
<TagSEO
|
||||
title={`${tag} - ${siteMetadata.title}`}
|
||||
description={`${tag} tags - ${siteMetadata.title}`}
|
||||
description={`${tag} tags - ${siteMetadata.author}`}
|
||||
/>
|
||||
<ListLayout posts={posts} title={title} />
|
||||
</>
|
||||
|
|
Loading…
Reference in a new issue