upstream #1
1
app/tag-data.json
Normal file
1
app/tag-data.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"markdown":1,"code":1,"features":1,"next-js":5,"math":1,"ols":1,"github":1,"guide":4,"tailwind":2,"holiday":1,"canada":1,"images":1,"writings":1,"book":1,"reflection":1,"multi-author":1,"feature":1}
|
@ -1,8 +1,9 @@
|
|||||||
import { slug } from 'github-slugger'
|
import { slug } from 'github-slugger'
|
||||||
import { getAllTags, allCoreContent } from 'pliny/utils/contentlayer'
|
import { allCoreContent } from 'pliny/utils/contentlayer'
|
||||||
import siteMetadata from '@/data/siteMetadata'
|
import siteMetadata from '@/data/siteMetadata'
|
||||||
import ListLayout from '@/layouts/ListLayout'
|
import ListLayout from '@/layouts/ListLayout'
|
||||||
import { allBlogs } from 'contentlayer/generated'
|
import { allBlogs } from 'contentlayer/generated'
|
||||||
|
import tagData from 'app/tag-data.json'
|
||||||
import { genPageMetadata } from 'app/seo'
|
import { genPageMetadata } from 'app/seo'
|
||||||
import { Metadata } from 'next'
|
import { Metadata } from 'next'
|
||||||
|
|
||||||
@ -21,8 +22,9 @@ export async function generateMetadata({ params }: { params: { tag: string } }):
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const generateStaticParams = async () => {
|
export const generateStaticParams = async () => {
|
||||||
const tags = await getAllTags(allBlogs)
|
const tagCounts = tagData as Record<string, number>
|
||||||
const paths = Object.keys(tags).map((tag) => ({
|
const tagKeys = Object.keys(tagCounts)
|
||||||
|
const paths = tagKeys.map((tag) => ({
|
||||||
tag: tag,
|
tag: tag,
|
||||||
}))
|
}))
|
||||||
return paths
|
return paths
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
import { getAllTags } from 'pliny/utils/contentlayer'
|
|
||||||
import Link from '@/components/Link'
|
import Link from '@/components/Link'
|
||||||
import Tag from '@/components/Tag'
|
import Tag from '@/components/Tag'
|
||||||
import { slug } from 'github-slugger'
|
import { slug } from 'github-slugger'
|
||||||
import { allBlogs } from 'contentlayer/generated'
|
import tagData from 'app/tag-data.json'
|
||||||
import { genPageMetadata } from 'app/seo'
|
import { genPageMetadata } from 'app/seo'
|
||||||
|
|
||||||
export const metadata = genPageMetadata({ title: 'Tags', description: 'Things I blog about' })
|
export const metadata = genPageMetadata({ title: 'Tags', description: 'Things I blog about' })
|
||||||
|
|
||||||
export default async function Page() {
|
export default async function Page() {
|
||||||
const tags = await getAllTags(allBlogs)
|
const tagCounts = tagData as Record<string, number>
|
||||||
const sortedTags = Object.keys(tags).sort((a, b) => tags[b] - tags[a])
|
const tagKeys = Object.keys(tagCounts)
|
||||||
|
const sortedTags = tagKeys.sort((a, b) => tagCounts[b] - tagCounts[a])
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="flex flex-col items-start justify-start divide-y divide-gray-200 dark:divide-gray-700 md:mt-24 md:flex-row md:items-center md:justify-center md:space-x-6 md:divide-y-0">
|
<div className="flex flex-col items-start justify-start divide-y divide-gray-200 dark:divide-gray-700 md:mt-24 md:flex-row md:items-center md:justify-center md:space-x-6 md:divide-y-0">
|
||||||
@ -19,7 +19,7 @@ export default async function Page() {
|
|||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex max-w-lg flex-wrap">
|
<div className="flex max-w-lg flex-wrap">
|
||||||
{Object.keys(tags).length === 0 && 'No tags found.'}
|
{tagKeys.length === 0 && 'No tags found.'}
|
||||||
{sortedTags.map((t) => {
|
{sortedTags.map((t) => {
|
||||||
return (
|
return (
|
||||||
<div key={t} className="mb-2 mr-5 mt-2">
|
<div key={t} className="mb-2 mr-5 mt-2">
|
||||||
@ -29,7 +29,7 @@ export default async function Page() {
|
|||||||
className="-ml-2 text-sm font-semibold uppercase text-gray-600 dark:text-gray-300"
|
className="-ml-2 text-sm font-semibold uppercase text-gray-600 dark:text-gray-300"
|
||||||
aria-label={`View posts tagged ${t}`}
|
aria-label={`View posts tagged ${t}`}
|
||||||
>
|
>
|
||||||
{` (${tags[t]})`}
|
{` (${tagCounts[t]})`}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import { defineDocumentType, ComputedFields, makeSource } from 'contentlayer/source-files'
|
import { defineDocumentType, ComputedFields, makeSource } from 'contentlayer/source-files'
|
||||||
|
import { writeFileSync } from 'fs'
|
||||||
import readingTime from 'reading-time'
|
import readingTime from 'reading-time'
|
||||||
|
import GithubSlugger from 'github-slugger'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
// Remark packages
|
// Remark packages
|
||||||
import remarkGfm from 'remark-gfm'
|
import remarkGfm from 'remark-gfm'
|
||||||
@ -38,6 +40,26 @@ const computedFields: ComputedFields = {
|
|||||||
toc: { type: 'string', resolve: (doc) => extractTocHeadings(doc.body.raw) },
|
toc: { type: 'string', resolve: (doc) => extractTocHeadings(doc.body.raw) },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count the occurrences of all tags across blog posts and write to json file
|
||||||
|
*/
|
||||||
|
function createTagCount(allBlogs) {
|
||||||
|
const tagCount: Record<string, number> = {}
|
||||||
|
allBlogs.forEach((file) => {
|
||||||
|
if (file.tags && file.draft !== true) {
|
||||||
|
file.tags.forEach((tag) => {
|
||||||
|
const formattedTag = GithubSlugger.slug(tag)
|
||||||
|
if (formattedTag in tagCount) {
|
||||||
|
tagCount[formattedTag] += 1
|
||||||
|
} else {
|
||||||
|
tagCount[formattedTag] = 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
writeFileSync('./app/tag-data.json', JSON.stringify(tagCount))
|
||||||
|
}
|
||||||
|
|
||||||
export const Blog = defineDocumentType(() => ({
|
export const Blog = defineDocumentType(() => ({
|
||||||
name: 'Blog',
|
name: 'Blog',
|
||||||
filePathPattern: 'blog/**/*.mdx',
|
filePathPattern: 'blog/**/*.mdx',
|
||||||
@ -113,4 +135,9 @@ export default makeSource({
|
|||||||
rehypePresetMinify,
|
rehypePresetMinify,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
onSuccess: async (importData) => {
|
||||||
|
const { allBlogs } = await importData()
|
||||||
|
createTagCount(allBlogs)
|
||||||
|
createSearchIndex(allBlogs)
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
"**/*.js",
|
"**/*.js",
|
||||||
"**/*.ts",
|
"**/*.ts",
|
||||||
"**/*.tsx",
|
"**/*.tsx",
|
||||||
|
"**/*.json",
|
||||||
".contentlayer/generated",
|
".contentlayer/generated",
|
||||||
".contentlayer/generated/**/*.json",
|
".contentlayer/generated/**/*.json",
|
||||||
".next/types/**/*.ts"
|
".next/types/**/*.ts"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user