Skip to content

Commit

Permalink
feature(changelog): changelog page
Browse files Browse the repository at this point in the history
  • Loading branch information
nikolovlazar committed Sep 8, 2022
1 parent 70419cb commit 1cb6d5f
Show file tree
Hide file tree
Showing 10 changed files with 156 additions and 47 deletions.
2 changes: 2 additions & 0 deletions contentlayer.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ const Changelog = defineDocumentType(() => ({
description: { type: 'string', required: true },
slug: { type: 'string' },
version: { type: 'string' },
releaseUrl: { type: 'string' },
releaseDate: { type: 'string' },
},
computedFields: {
frontMatter: {
Expand Down
5 changes: 3 additions & 2 deletions i18n/ui.json
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,8 @@
"sponsor": "Sponsor"
},
"table-of-content": {
"on-this-page": "On this page"
"on-this-page": "On this page",
"versions": "Versions"
},
"vercel-callout": {
"deployed-by": "Deployed by"
Expand All @@ -219,4 +220,4 @@
"message": "A collection of beautiful websites that are built in Chakra UI",
"submit-project-button-title": "Submit your project"
}
}
}
86 changes: 86 additions & 0 deletions layouts/changelog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import PageContainer from 'components/page-container'
import Sidebar from 'components/sidebar/sidebar'
import componentsSidebar from 'configs/components.sidebar.json'
import gettingStartedSidebar from 'configs/getting-started.sidebar.json'
import hooksSidebar from 'configs/hooks.sidebar.json'
import styledSystemSidebar from 'configs/styled-system.sidebar.json'
import tutorialSidebar from 'configs/tutorial.sidebar.json'
import communitySidebar from 'configs/community.sidebar.json'
import semverRSort from 'semver/functions/rsort'
import { ReactNode } from 'react'
import { RouteItem } from 'utils/get-route-context'
import { Frontmatter } from 'src/types/frontmatter'
import { List, ListItem } from '@chakra-ui/react'
import SidebarLink from 'components/sidebar/sidebar-link'
import { allChangelogs } from 'contentlayer/generated'
import TocNav from 'components/toc-nav'
import { t } from 'utils/i18n'

export function getRoutes(slug: string): RouteItem[] {
// for home page, use docs sidebar
if (slug === '/') {
return gettingStartedSidebar.routes as RouteItem[]
}

const configMap = {
'/getting-started': gettingStartedSidebar,
'/docs/styled-system': styledSystemSidebar,
'/docs/hooks': hooksSidebar,
'/docs/components': componentsSidebar,
'/tutorial': tutorialSidebar,
'/community': communitySidebar,
}

const [, sidebar] =
Object.entries(configMap).find(([path]) => slug.startsWith(path)) ?? []

const routes = sidebar?.routes ?? []
return routes as RouteItem[]
}

export function getVersions(): RouteItem[] {
return semverRSort(
allChangelogs
.filter(({ version }) => version.startsWith('2.'))
.map(({ version }) => version),
).map((version) => ({
title: `v${version}`,
path: `/changelog/${version}`,
}))
}

interface MDXLayoutProps {
frontmatter: Frontmatter
children: ReactNode
hideToc?: boolean
maxWidth?: string
}

export default function MDXLayout(props: MDXLayoutProps) {
const { frontmatter, children, maxWidth } = props

const routes = getRoutes(frontmatter.slug)
const versions = getVersions()

return (
<PageContainer
hideToc={true}
maxWidth={maxWidth}
frontmatter={frontmatter}
leftSidebar={<Sidebar routes={routes} />}
rightSidebar={
<TocNav title={t('component.table-of-content.versions')}>
<List mt={2}>
{versions.map(({ title, path }) => (
<ListItem key={path}>
<SidebarLink href={path}>{title}</SidebarLink>
</ListItem>
))}
</List>
</TocNav>
}
>
{children}
</PageContainer>
)
}
2 changes: 1 addition & 1 deletion layouts/mdx.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export default function MDXLayout(props: MDXLayoutProps) {
hideToc={hideToc}
maxWidth={maxWidth}
frontmatter={frontmatter}
sidebar={<Sidebar routes={routes} />}
leftSidebar={<Sidebar routes={routes} />}
pagination={
<Pagination
next={routeContext.nextRoute}
Expand Down
13 changes: 10 additions & 3 deletions pages/changelog/[version].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ import semverMaxSatisfying from 'semver/ranges/max-satisfying'
import { useMDXComponent } from 'next-contentlayer/hooks'
import React from 'react'
import { MDXComponents } from 'components/mdx-components'
import MDXLayout from 'layouts/mdx'
import ChangelogLayout from 'layouts/changelog'

export default function Page({
doc,
}: InferGetStaticPropsType<typeof getStaticProps>) {
const Component = useMDXComponent(doc.body.code)
return (
<MDXLayout frontmatter={doc.frontMatter}>
<ChangelogLayout hideToc frontmatter={doc.frontMatter}>
<Component components={MDXComponents} />
</MDXLayout>
</ChangelogLayout>
)
}

Expand All @@ -39,6 +39,13 @@ export const getStaticProps = async (ctx) => {
allChangelogs.map(({ version }) => version),
'*',
)

return {
redirect: {
destination: `/changelog/${versionParam}`,
permanent: true,
},
}
}

const doc = allChangelogs.find(({ version }) => version === versionParam)
Expand Down
2 changes: 1 addition & 1 deletion pages/resources.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ function Resources() {

return (
<PageContainer
sidebar={<Sidebar routes={routes} />}
leftSidebar={<Sidebar routes={routes} />}
frontmatter={{
title: t('resources.title'),
description: t('resources.description'),
Expand Down
9 changes: 6 additions & 3 deletions src/components/page-container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,17 @@ interface PageContainerProps {
hideToc?: boolean
maxWidth?: string
children: React.ReactNode
sidebar?: React.ReactElement
leftSidebar?: React.ReactElement
rightSidebar?: React.ReactElement
pagination?: React.ReactElement
}

function PageContainer(props: PageContainerProps) {
const {
frontmatter,
children,
sidebar,
leftSidebar,
rightSidebar,
pagination,
hideToc,
maxWidth = '48rem',
Expand All @@ -69,7 +71,7 @@ function PageContainer(props: PageContainerProps) {
<Header />
<Box as='main' className='main-content' w='full' maxW='8xl' mx='auto'>
<Box display={{ md: 'flex' }}>
{sidebar || null}
{leftSidebar || null}
<Box flex='1' minW='0'>
<SkipNavContent />
<Box id='content' px={5} mx='auto' minH='76vh'>
Expand Down Expand Up @@ -105,6 +107,7 @@ function PageContainer(props: PageContainerProps) {
headings={headings}
/>
)}
{rightSidebar}
</Flex>
</Box>
</Box>
Expand Down
10 changes: 4 additions & 6 deletions src/components/sidebar/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,10 @@ import SidebarLink from './sidebar-link'

const sortRoutes = (routes: RouteItem[]) => {
return routes.sort(({ title: titleA }, { title: titleB }) => {
if (titleA < titleB)
return -1;
if (titleA > titleB)
return 1;
return 0;
});
if (titleA < titleB) return -1
if (titleA > titleB) return 1
return 0
})
}

export type SidebarContentProps = Routes & {
Expand Down
34 changes: 3 additions & 31 deletions src/components/table-of-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import * as React from 'react'
import { useScrollSpy } from 'hooks/use-scrollspy'
import { t } from 'utils/i18n'
import type { FrontmatterHeading } from 'src/types/frontmatter'
import TocNav from './toc-nav'

interface TableOfContentProps extends BoxProps {
headings: FrontmatterHeading[]
Expand All @@ -27,36 +28,7 @@ function TableOfContent(props: TableOfContentProps) {
const linkColor = useColorModeValue('gray.600', 'gray.400')
const linkHoverColor = useColorModeValue('gray.900', 'gray.600')
return (
<Box
as='nav'
aria-labelledby='toc-title'
width='16rem'
flexShrink={0}
display={{ base: 'none', xl: 'block' }}
position='sticky'
py='10'
pr='4'
top='6rem'
right='0'
fontSize='sm'
alignSelf='start'
maxHeight='calc(100vh - 8rem)'
overflowY='auto'
sx={{ overscrollBehavior: 'contain' }}
{...rest}
>
<Text
as='h2'
id='toc-title'
textTransform='uppercase'
fontWeight='bold'
fontSize='xs'
color='gray.700'
_dark={{ color: 'gray.400' }}
letterSpacing='wide'
>
{t('component.table-of-content.on-this-page')}
</Text>
<TocNav title={t('component.table-of-content.on-this-page')} {...rest}>
<OrderedList spacing={1} ml='0' mt='4' styleType='none'>
{headings.map(({ id, text, level }) => (
<ListItem key={id} title={text} ml={level === 'h3' ? '4' : undefined}>
Expand All @@ -76,7 +48,7 @@ function TableOfContent(props: TableOfContentProps) {
</ListItem>
))}
</OrderedList>
</Box>
</TocNav>
)
}

Expand Down
40 changes: 40 additions & 0 deletions src/components/toc-nav.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Box, BoxProps, Text } from '@chakra-ui/react'

export default function TocNav({ children, title, ...rest }: BoxProps) {
return (
<Box
as='nav'
aria-labelledby='toc-title'
width='16rem'
flexShrink={0}
display={{ base: 'none', xl: 'block' }}
position='sticky'
py='10'
pr='4'
top='6rem'
right='0'
fontSize='sm'
alignSelf='start'
maxHeight='calc(100vh - 8rem)'
overflowY='auto'
sx={{ overscrollBehavior: 'contain' }}
{...rest}
>
{title && (
<Text
as='h2'
id='toc-title'
textTransform='uppercase'
fontWeight='bold'
fontSize='xs'
color='gray.700'
_dark={{ color: 'gray.400' }}
letterSpacing='wide'
>
{title}
</Text>
)}
{children}
</Box>
)
}

0 comments on commit 1cb6d5f

Please sign in to comment.