[docs] Simplify paths for uncategorised pages (#1619)
This PR changes the paths that we use for uncategorised pages on the docs site. It also redirects the old paths to the new ones. ``` // BEFORE tldraw.dev/docs/ucg/shapes // AFTER tldraw.dev/docs/shapes ``` I think that this is more intuitive, and will make the links that we share a bit clearer. eg: As a by-product, it fixes some broken links from the introduction page. As a trade-off, this PR makes our pathing system a bit more complicated. But I don't think it's tooooo bad? WDYT? ### Change Type - [x] `documentation` — Changes to the documentation only[^2] [^1]: publishes a `patch` release, for devDependencies use `internal` [^2]: will not publish a new version ### Test Plan 1. Navigate to `/docs/shapes` on the docs site. 2. Make sure that it goes to the Shapes page. 3. Do the same for `/docs/ucg/shapes` ### Release Notes - Documentation: Cleaned up some paths.
This commit is contained in:
parent
57bb341593
commit
8329b1da89
3 changed files with 90 additions and 26 deletions
|
@ -5,6 +5,15 @@ const nextConfig = {
|
||||||
scrollRestoration: true,
|
scrollRestoration: true,
|
||||||
},
|
},
|
||||||
transpilePackages: ['@tldraw/utils'],
|
transpilePackages: ['@tldraw/utils'],
|
||||||
|
async redirects() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
source: '/:sectionId/ucg/:articleId',
|
||||||
|
destination: '/:sectionId/:articleId',
|
||||||
|
permanent: true,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = nextConfig
|
module.exports = nextConfig
|
||||||
|
|
|
@ -18,7 +18,8 @@ import { GetStaticPaths, GetStaticProps } from 'next'
|
||||||
import { MDXRemoteSerializeResult } from 'next-mdx-remote'
|
import { MDXRemoteSerializeResult } from 'next-mdx-remote'
|
||||||
import { useTheme } from 'next-themes'
|
import { useTheme } from 'next-themes'
|
||||||
|
|
||||||
interface Props {
|
export type ArticleProps = {
|
||||||
|
type: 'article'
|
||||||
sidebar: SidebarContentList
|
sidebar: SidebarContentList
|
||||||
section: Section
|
section: Section
|
||||||
category: Category
|
category: Category
|
||||||
|
@ -34,7 +35,7 @@ export default function ArticlePage({
|
||||||
article,
|
article,
|
||||||
links,
|
links,
|
||||||
sidebar,
|
sidebar,
|
||||||
}: Props) {
|
}: ArticleProps) {
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -55,12 +56,13 @@ export default function ArticlePage({
|
||||||
|
|
||||||
export const getStaticPaths: GetStaticPaths = async () => {
|
export const getStaticPaths: GetStaticPaths = async () => {
|
||||||
const sections = await getSections()
|
const sections = await getSections()
|
||||||
const paths: { params: { sectionId: string; categoryId: string; articleId: string } }[] = []
|
const paths: { params: { sectionId: string; childId: string; articleId: string } }[] = []
|
||||||
|
|
||||||
for (const section of sections) {
|
for (const section of sections) {
|
||||||
for (const category of section.categories) {
|
for (const category of section.categories) {
|
||||||
|
if (category.id === 'ucg') continue
|
||||||
for (const articleId of category.articleIds) {
|
for (const articleId of category.articleIds) {
|
||||||
paths.push({ params: { sectionId: section.id, categoryId: category.id, articleId } })
|
paths.push({ params: { sectionId: section.id, childId: category.id, articleId } })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,9 +70,9 @@ export const getStaticPaths: GetStaticPaths = async () => {
|
||||||
return { paths, fallback: false }
|
return { paths, fallback: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getStaticProps: GetStaticProps<Props> = async (ctx) => {
|
export const getStaticProps: GetStaticProps<ArticleProps> = async (ctx) => {
|
||||||
const sectionId = ctx.params?.sectionId?.toString() as string
|
const sectionId = ctx.params?.sectionId?.toString() as string
|
||||||
const categoryId = ctx.params?.categoryId?.toString() as string
|
const categoryId = ctx.params?.childId?.toString() as string
|
||||||
const articleId = ctx.params?.articleId?.toString()
|
const articleId = ctx.params?.articleId?.toString()
|
||||||
if (!articleId) throw Error()
|
if (!articleId) throw Error()
|
||||||
|
|
||||||
|
@ -81,5 +83,15 @@ export const getStaticProps: GetStaticProps<Props> = async (ctx) => {
|
||||||
const links = await getLinks(articleId)
|
const links = await getLinks(articleId)
|
||||||
const mdxSource = await getArticleSource(articleId)
|
const mdxSource = await getArticleSource(articleId)
|
||||||
|
|
||||||
return { props: { article, section, category, sidebar, links, mdxSource } }
|
return {
|
||||||
|
props: {
|
||||||
|
type: 'article',
|
||||||
|
article,
|
||||||
|
section,
|
||||||
|
category,
|
||||||
|
sidebar,
|
||||||
|
links,
|
||||||
|
mdxSource,
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -2,11 +2,14 @@ import { Breadcrumb } from '@/components/Breadcrumb'
|
||||||
import { Mdx } from '@/components/Mdx'
|
import { Mdx } from '@/components/Mdx'
|
||||||
import { MetaHead } from '@/components/MetaHead'
|
import { MetaHead } from '@/components/MetaHead'
|
||||||
import { Sidebar } from '@/components/Sidebar'
|
import { Sidebar } from '@/components/Sidebar'
|
||||||
|
import ArticlePage from '@/pages/[sectionId]/[childId]/[articleId]'
|
||||||
import { Article, Category, Section, SidebarContentList } from '@/types/content-types'
|
import { Article, Category, Section, SidebarContentList } from '@/types/content-types'
|
||||||
import {
|
import {
|
||||||
|
getArticle,
|
||||||
getArticleSource,
|
getArticleSource,
|
||||||
getArticles,
|
getArticles,
|
||||||
getCategory,
|
getCategory,
|
||||||
|
getLinks,
|
||||||
getSection,
|
getSection,
|
||||||
getSections,
|
getSections,
|
||||||
} from '@/utils/content'
|
} from '@/utils/content'
|
||||||
|
@ -15,8 +18,10 @@ import { GetStaticPaths, GetStaticProps } from 'next'
|
||||||
import { MDXRemoteSerializeResult } from 'next-mdx-remote'
|
import { MDXRemoteSerializeResult } from 'next-mdx-remote'
|
||||||
import { useTheme } from 'next-themes'
|
import { useTheme } from 'next-themes'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
|
import { ArticleProps } from './[articleId]'
|
||||||
|
|
||||||
type Props = {
|
type CategoryProps = {
|
||||||
|
type: 'category'
|
||||||
sidebar: SidebarContentList
|
sidebar: SidebarContentList
|
||||||
section: Section
|
section: Section
|
||||||
category: Category
|
category: Category
|
||||||
|
@ -24,15 +29,17 @@ type Props = {
|
||||||
mdxSource: MDXRemoteSerializeResult | null
|
mdxSource: MDXRemoteSerializeResult | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function CategoryListPage({
|
type ChildProps = CategoryProps | ArticleProps
|
||||||
sidebar,
|
|
||||||
mdxSource,
|
export default function CategoryListPage(props: ChildProps) {
|
||||||
articles,
|
|
||||||
section,
|
|
||||||
category,
|
|
||||||
}: Props) {
|
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
|
|
||||||
|
if (props.type === 'article') {
|
||||||
|
return <ArticlePage {...props} />
|
||||||
|
}
|
||||||
|
|
||||||
|
const { sidebar, section, category, articles, mdxSource } = props
|
||||||
|
|
||||||
const ungrouped: Article[] = []
|
const ungrouped: Article[] = []
|
||||||
const groupedArticles = Object.fromEntries(
|
const groupedArticles = Object.fromEntries(
|
||||||
category.groups.map((group) => [group.id, { group, articles: [] as Article[] }])
|
category.groups.map((group) => [group.id, { group, articles: [] as Article[] }])
|
||||||
|
@ -92,12 +99,18 @@ export default function CategoryListPage({
|
||||||
|
|
||||||
export const getStaticPaths: GetStaticPaths = async () => {
|
export const getStaticPaths: GetStaticPaths = async () => {
|
||||||
const sections = await getSections()
|
const sections = await getSections()
|
||||||
const paths: { params: { sectionId: string; categoryId: string } }[] = []
|
const paths: { params: { sectionId: string; childId: string } }[] = []
|
||||||
|
|
||||||
for (const section of sections) {
|
for (const section of sections) {
|
||||||
if (section.categories) {
|
if (section.categories) {
|
||||||
for (const category of section.categories) {
|
for (const category of section.categories) {
|
||||||
paths.push({ params: { sectionId: section.id, categoryId: category.id } })
|
paths.push({ params: { sectionId: section.id, childId: category.id } })
|
||||||
|
|
||||||
|
// Add paths for uncategorized articles as well
|
||||||
|
if (category.id !== 'ucg') continue
|
||||||
|
for (const articleId of category.articleIds) {
|
||||||
|
paths.push({ params: { sectionId: section.id, childId: articleId } })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,23 +118,53 @@ export const getStaticPaths: GetStaticPaths = async () => {
|
||||||
return { paths, fallback: false }
|
return { paths, fallback: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getStaticProps: GetStaticProps<Props> = async (ctx) => {
|
export const getStaticProps: GetStaticProps<ChildProps> = async (ctx) => {
|
||||||
const sectionId = ctx.params?.sectionId?.toString() as string
|
const sectionId = ctx.params?.sectionId?.toString() as string
|
||||||
const categoryId = ctx.params?.categoryId?.toString()
|
const childId = ctx.params?.childId?.toString()
|
||||||
if (!categoryId || !sectionId) throw Error()
|
if (!childId || !sectionId) throw Error()
|
||||||
|
|
||||||
const sidebar = await getSidebarContentList({
|
|
||||||
sectionId,
|
|
||||||
categoryId,
|
|
||||||
})
|
|
||||||
|
|
||||||
const articles = await getArticles()
|
const articles = await getArticles()
|
||||||
const section = await getSection(sectionId)
|
const section = await getSection(sectionId)
|
||||||
|
|
||||||
|
// If the path goes to an uncategorized article, show the article page
|
||||||
|
if (!section.categories.some((c) => c.id === childId)) {
|
||||||
|
const categoryId = 'ucg'
|
||||||
|
const articleId = childId
|
||||||
|
const sidebar = await getSidebarContentList({ sectionId, categoryId, articleId })
|
||||||
|
const category = await getCategory(sectionId, categoryId)
|
||||||
|
const article = await getArticle(articleId)
|
||||||
|
const links = await getLinks(articleId)
|
||||||
|
const mdxSource = await getArticleSource(articleId)
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
type: 'article',
|
||||||
|
sidebar,
|
||||||
|
section,
|
||||||
|
category,
|
||||||
|
article,
|
||||||
|
links,
|
||||||
|
mdxSource,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, show the category page
|
||||||
|
const categoryId = childId
|
||||||
|
const sidebar = await getSidebarContentList({ sectionId, categoryId })
|
||||||
const category = await getCategory(sectionId, categoryId)
|
const category = await getCategory(sectionId, categoryId)
|
||||||
const categoryArticles = category.articleIds.map((id) => articles[id])
|
const categoryArticles = category.articleIds.map((id) => articles[id])
|
||||||
|
|
||||||
const article = articles[categoryId + '_index'] ?? null
|
const article = articles[categoryId + '_index'] ?? null
|
||||||
const mdxSource = article ? await getArticleSource(categoryId + '_index') : null
|
const mdxSource = article ? await getArticleSource(categoryId + '_index') : null
|
||||||
|
|
||||||
return { props: { sidebar, section, category, articles: categoryArticles, mdxSource } }
|
return {
|
||||||
|
props: {
|
||||||
|
type: 'category',
|
||||||
|
sidebar,
|
||||||
|
section,
|
||||||
|
category,
|
||||||
|
articles: categoryArticles,
|
||||||
|
mdxSource,
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue