refactor: revamp documentation (#196)

Co-authored-by: Valerio Ageno <valerio.ageno@qonto.com>
This commit is contained in:
Valerio Ageno
2024-12-07 12:06:08 +01:00
committed by GitHub
parent c76464bf8a
commit c491ece8c5
25 changed files with 651 additions and 129 deletions
@@ -1,24 +1,31 @@
import type { JSX } from 'react'
import { AppShell, Burger, Button, Flex } from '@mantine/core'
import { AppShell, Box, Burger, Button, Flex } from '@mantine/core'
import { Link } from 'tuono'
import Actions from './actions'
interface NavbarProps {
opened: boolean
toggle: () => void
}
export default function Navbar({ opened, toggle }: NavbarProps): JSX.Element {
export default function Navbar({ toggle }: NavbarProps): JSX.Element {
return (
<AppShell.Header p="sm">
<Flex justify="space-between">
<Button component={Link} href="/" variant="transparent" p={0} fz={28}>
<Button
component={Link}
href="/"
variant="transparent"
p={0}
fz={28}
hiddenFrom="sm"
>
Tuono
</Button>
<Box />
<Flex align="center" gap={8}>
<Actions />
<Burger opened={opened} onClick={toggle} hiddenFrom="sm" size="sm" />
<Burger onClick={toggle} hiddenFrom="sm" size="sm" />
</Flex>
</Flex>
</AppShell.Header>
@@ -0,0 +1,266 @@
import type { ReactNode } from 'react'
interface SidebarElementType<T> {
type: T
}
interface SidebarLink extends SidebarElementType<'element'> {
label: string
href: string
children?: SidebarLink[]
leftIcon?: ReactNode
}
interface SidebarTitle extends SidebarElementType<'title'> {
label: string
}
type SidebarElements =
| SidebarElementType<'divider'>
| SidebarLink
| SidebarTitle
export const sidebarElements: SidebarElements[] = [
{
type: 'element',
label: 'Home',
href: '/',
},
{
type: 'element',
label: 'Getting started',
href: '#focus',
children: [
{
type: 'element',
label: 'Installation',
href: '/documentation/installation',
},
{
type: 'element',
label: 'How is tuono different?',
href: '/documentation/how-is-tuono-different',
},
],
},
{
type: 'element',
label: 'Tutorial',
href: '#focus',
children: [
{
type: 'element',
href: '/documentation/tutorial',
label: 'Intro',
},
{
type: 'element',
href: '/documentation/tutorial/development-setup',
label: 'Development setup',
},
{
type: 'element',
href: '/documentation/tutorial/api-fetching',
label: 'API fetching',
},
{
type: 'element',
href: '/documentation/tutorial/components',
label: 'Components',
},
{
type: 'element',
href: '/documentation/tutorial/dynamic-routes',
label: 'Dynamic routes',
},
{
type: 'element',
href: '/documentation/tutorial/error-handling',
label: 'Error handling',
},
{
type: 'element',
href: '/documentation/tutorial/seo',
label: 'SEO and meta tags',
},
{
type: 'element',
href: '/documentation/tutorial/redirections',
label: 'Redirections',
},
{
type: 'element',
href: '/documentation/tutorial/production',
label: 'Production build',
},
{
type: 'element',
href: '/documentation/tutorial/conclusion',
label: 'Conclusion',
},
],
},
{ type: 'divider' },
{ type: 'title', label: 'Overview' },
{
type: 'element',
label: 'Routing',
href: '#focus',
children: [
{
type: 'element',
label: 'Defining routes',
href: '/documentation/routing/defining-routes',
},
{
type: 'element',
label: 'Pages',
href: '/documentation/routing/pages',
},
{
type: 'element',
label: 'Loading state',
href: '/documentation/routing/loading-state',
},
{
type: 'element',
label: 'Dynamic routes',
href: '/documentation/routing/dynamic-routes',
},
{
type: 'element',
label: 'Layouts',
href: '/documentation/routing/layouts',
},
{
type: 'element',
label: 'Link and navigation',
href: '/documentation/routing/link-and-navigation',
},
{
type: 'element',
label: 'Redirecting',
href: '/documentation/routing/redirecting',
},
],
},
{
type: 'element',
label: 'Rendering',
href: '#focus',
children: [
{
type: 'element',
label: 'Server side rendering',
href: '/documentation/rendering/server-side-rendering',
},
{
type: 'element',
label: 'Static site rendering',
href: '/documentation/rendering/static-site-rendering',
},
],
},
{
type: 'element',
label: 'Styles',
href: '#focus',
children: [
{
type: 'element',
label: 'CSS modules',
href: '/documentation/styles/css-modules',
},
],
},
{
type: 'element',
label: 'Integrations',
href: '#focus',
children: [
{
type: 'element',
label: 'MDX',
href: '/documentation/integrations/mdx',
},
],
},
{
type: 'element',
label: 'Core concepts',
href: '#focus',
children: [
{
type: 'element',
label: 'Multithreading',
href: '/documentation/core-concepts/multithreading',
},
],
},
{ type: 'divider' },
{ type: 'title', label: 'API reference' },
{
type: 'element',
label: 'Components',
href: '#focus',
children: [
{
type: 'element',
label: 'Head',
href: '/documentation/components/head',
},
{
type: 'element',
label: 'Link',
href: '/documentation/components/link',
},
],
},
{
type: 'element',
label: 'Hooks',
href: '#focus',
children: [
{
type: 'element',
label: 'useRouter',
href: '/documentation/hooks/use-router',
},
],
},
{
type: 'element',
label: 'CLI',
href: '/documentation/cli',
},
{
type: 'element',
label: 'Application state',
href: '/documentation/application-state',
},
{
type: 'element',
label: 'tuono.config.ts',
href: '/documentation/configuration',
},
{ type: 'divider' },
{
type: 'element',
label: 'Contributing',
href: '#focus',
leftIcon: '✨',
children: [
{
type: 'element',
label: 'Guildelines',
href: '/documentation/contributing',
},
{
type: 'element',
label: 'Local development',
href: '/documentation/contributing/local-development',
},
],
},
]
@@ -1,6 +1,17 @@
.link {
border-radius: 8px;
margin-top: 0.25rem;
line-height: 1.25rem;
line-height: 1rem;
font-weight: 500;
transition: 0.3s;
}
.link span {
font-size: 14px !important;
color: var(--mantine-color-sidebar-gray);
}
.link:hover span,
.active span {
color: var(--mantine-color-sidebar-text-hover);
}
@@ -1,6 +1,6 @@
import type { JSX, ReactNode } from 'react'
import { useState } from 'react'
import { NavLink, type NavLinkProps } from '@mantine/core'
import clsx from 'clsx'
import { Link, useRouter } from 'tuono'
import { IconChevronRight } from '@tabler/icons-react'
@@ -17,24 +17,19 @@ export default function SidebarLink(
props: SidebarLinkProps & NavLinkProps,
): JSX.Element {
const { pathname } = useRouter()
const [isOpen, setIsOpen] = useState<boolean>(!!props.defaultOpened)
const isActive = pathname === props.href
const internalProps = {
active: pathname === props.href,
className: styles.link,
active: isActive,
className: clsx(styles.link, isActive && styles.active),
rightSection: props.children && (
<IconChevronRight
size="1.2rem"
stroke={1.5}
className="mantine-rotate-rtl"
onClick={(e) => {
e.preventDefault()
e.stopPropagation()
setIsOpen((state) => !state)
}}
/>
),
opened: isOpen,
autoContrast: true,
...props,
}
@@ -1,104 +1,106 @@
import type { JSX } from 'react'
import { AppShell } from '@mantine/core'
import {
AppShell,
Badge,
Flex,
Divider,
Title,
Button,
ScrollArea,
Text,
} from '@mantine/core'
import { IconX } from '@tabler/icons-react'
import { useMediaQuery } from '@mantine/hooks'
import { sidebarElements } from './config'
import SidebarLink from './sidebar-link'
interface SidebarProps {
close: () => void
}
function SidebarHeader(): JSX.Element {
const isSm = useMediaQuery('(min-width: 48em)')
return (
<AppShell.Section>
<Flex mb={20} w="100%" justify="space-between">
<Flex
gap={10}
align="center"
w={isSm ? '100%' : 'auto'}
justify="center"
>
<Title order={3}>Tuono</Title>
<Badge mt={4} size="xs" variant="outline">
Docs
</Badge>
</Flex>
<Button onClick={close} hiddenFrom="sm" variant="transparent" p="0">
<IconX />
</Button>
</Flex>
</AppShell.Section>
)
}
function SidebarElements({ close }: SidebarProps): JSX.Element {
return (
<AppShell.Section component={ScrollArea}>
{sidebarElements.map((el, i) => {
if (el.type === 'divider') {
return <Divider my="md" mx={10} />
}
if (el.type === 'title') {
return (
<Text
size="xs"
fw={700}
fz={12}
pl={12}
py={5}
children={el.label}
/>
)
}
if (el.children?.length) {
return (
<SidebarLink
href={el.href}
label={el.label}
key={i}
leftSection={el.leftIcon}
>
{el.children.map((child, index) => (
<SidebarLink
href={child.href}
label={child.label}
key={index}
onClick={close}
/>
))}
</SidebarLink>
)
}
return (
<SidebarLink
href={el.href}
label={el.label}
onClick={close}
key={i}
/>
)
})}
</AppShell.Section>
)
}
export default function Sidebar({ close }: SidebarProps): JSX.Element {
return (
<AppShell.Navbar p="md">
<SidebarLink href="/" label="Home" onClick={close} />
<SidebarLink
href="/documentation/installation"
label="Installation"
onClick={close}
/>
<SidebarLink
href="/documentation/tutorial"
label="Tutorial"
defaultOpened
onClick={close}
>
<SidebarLink
href="/documentation/tutorial/development-setup"
label="Development setup"
onClick={close}
/>
<SidebarLink
href="/documentation/tutorial/api-fetching"
label="API fetching"
onClick={close}
/>
<SidebarLink
href="/documentation/tutorial/components"
label="Components"
onClick={close}
/>
<SidebarLink
href="/documentation/tutorial/dynamic-routes"
label="Dynamic routes"
onClick={close}
/>
<SidebarLink
href="/documentation/tutorial/error-handling"
label="Error handling"
onClick={close}
/>
<SidebarLink
href="/documentation/tutorial/seo"
label="SEO and meta tags"
onClick={close}
/>
<SidebarLink
href="/documentation/tutorial/redirections"
label="Server redirection"
onClick={close}
/>
<SidebarLink
href="/documentation/tutorial/production"
label="Production build"
onClick={close}
/>
<SidebarLink
href="/documentation/tutorial/conclusion"
label="Conclusion"
onClick={close}
/>
</SidebarLink>
<SidebarLink href="/documentation/cli" label="CLI" onClick={close} />
<SidebarLink
label="Application state"
href="/documentation/application-state"
onClick={close}
/>
<SidebarLink
label="Routing"
href="/documentation/routing"
onClick={close}
>
<SidebarLink
href="/documentation/routing/intro"
label="Project structure"
onClick={close}
/>
</SidebarLink>
<SidebarLink
label="Contributing"
href="/documentation/contributing"
leftSection="✨"
onClick={close}
>
<SidebarLink
href="/documentation/contributing/local-development"
label="Local development"
onClick={close}
/>
</SidebarLink>
<SidebarHeader />
<SidebarElements close={close} />
</AppShell.Navbar>
)
}
+25 -3
View File
@@ -7,6 +7,7 @@ import {
AppShell,
Container,
} from '@mantine/core'
import type { CSSVariablesResolver } from '@mantine/core'
import { useDisclosure } from '@mantine/hooks'
import { Head } from 'tuono'
@@ -25,7 +26,7 @@ interface RootRouteProps {
const theme = createTheme({
primaryColor: 'violet',
primaryShade: { light: 6, dark: 9 },
fontFamily: 'Roboto',
fontFamily: 'Inter',
respectReducedMotion: true,
radius: {
xs: '8px',
@@ -60,6 +61,26 @@ const theme = createTheme({
},
},
},
other: {
sidebarGrayLight: '#495057',
sidebarGrayDark: '#adb5bd',
sidebarTextHoverLight: '#212529',
sidebarTextHoverDark: '#f8f9fa',
},
})
const resolver: CSSVariablesResolver = (th) => ({
variables: {},
light: {
'--mantine-color-sidebar-gray': th.other.sidebarGrayLight as string,
'--mantine-color-sidebar-text-hover': th.other
.sidebarTextHoverLight as string,
},
dark: {
'--mantine-color-sidebar-gray': th.other.sidebarGrayDark as string,
'--mantine-color-sidebar-text-hover': th.other
.sidebarTextHoverDark as string,
},
})
export default function RootRoute({ children }: RootRouteProps): JSX.Element {
@@ -77,8 +98,9 @@ export default function RootRoute({ children }: RootRouteProps): JSX.Element {
<link rel="manifest" href="/site.webmanifest" />
</Head>
<ColorSchemeScript />
<MantineProvider theme={theme}>
<MantineProvider theme={theme} cssVariablesResolver={resolver}>
<AppShell
layout="alt"
header={{ height: 60 }}
navbar={{
width: 300,
@@ -86,7 +108,7 @@ export default function RootRoute({ children }: RootRouteProps): JSX.Element {
collapsed: { mobile: !opened },
}}
>
<Navbar opened={opened} toggle={toggle} />
<Navbar toggle={toggle} />
<Sidebar close={toggle} />
<AppShell.Main>
<Container id="mdx-root" component="article" size="md" p={20}>
@@ -0,0 +1,14 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - Head"
canonical="https://tuono.dev/documentation/components/head"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'Components' }]} />
# Head
TODO
@@ -0,0 +1,14 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - Link"
canonical="https://tuono.dev/documentation/components/link"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'Components' }]} />
# Link
TODO
@@ -0,0 +1,14 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - tuono.config.ts"
canonical="https://tuono.dev/documentation/configuration"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'Configuration' }]} />
# Configuration
TODO
@@ -0,0 +1,14 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - Multithreading"
canonical="https://tuono.dev/documentation/core-concepts/multithreading"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'Core concepts' }]} />
# Multithreading
TODO
@@ -0,0 +1,14 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - useRouter"
canonical="https://tuono.dev/documentation/hooks/use-router"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'Hooks' }]} />
# useRouter
TODO
@@ -0,0 +1,14 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - tuono.config.ts"
canonical="https://tuono.dev/documentation/how-is-tuono-different"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'How is tuono different?' }]} />
# How is tuono different?
TODO
@@ -0,0 +1,14 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - MDX"
canonical="https://tuono.dev/documentation/integrations/mdx"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'Integrations' }]} />
# MDX
TODO
@@ -0,0 +1,14 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - Server side rendering"
canonical="https://tuono.dev/documentation/rendering/server-side-rendering"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'Rendering' }]} />
# SSR
TODO
@@ -0,0 +1,14 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - Static site rendering"
canonical="https://tuono.dev/documentation/rendering/static-site-rendering"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'Rendering' }]} />
# Static Site Rendering
TODO
@@ -0,0 +1,14 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - Routing"
canonical="https://tuono.dev/documentation/routing/defining-routes"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'Defining routes' }]} />
# Defining routes
Todo
@@ -0,0 +1,14 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - Routing"
canonical="https://tuono.dev/documentation/routing/dynamic-routes"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'Dynamic routes' }]} />
# Loading state
Todo
@@ -1,19 +0,0 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - Routing"
canonical="https://tuono.dev/documentation/routing"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs
breadcrumbs={[
{ label: 'Routing', href: '/documentation/routing' },
{ label: 'Project structure' },
]}
/>
# Project structure
Todo
@@ -0,0 +1,14 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - Routing"
canonical="https://tuono.dev/documentation/routing/layouts"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'Layouts' }]} />
# Layouts
Todo
@@ -0,0 +1,14 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - Routing"
canonical="https://tuono.dev/documentation/routing/link-and-navigation"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'Link and navigation' }]} />
# Link and navigation
Todo
@@ -0,0 +1,14 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - Routing"
canonical="https://tuono.dev/documentation/routing/loading-state"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'Loading state' }]} />
# Loading state
Todo
@@ -0,0 +1,14 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - Routing"
canonical="https://tuono.dev/documentation/routing/pages"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'Pages' }]} />
# Pages
Todo
@@ -0,0 +1,14 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - Routing"
canonical="https://tuono.dev/documentation/routing/redirecting"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'Redirecting' }]} />
# Redirecting
Todo
@@ -0,0 +1,14 @@
import MetaTags from '@/components/meta-tags'
<MetaTags
title="Tuono - CSS Modules"
canonical="https://tuono.dev/documentation/styles/css-modules"
/>
import Breadcrumbs, { Element } from '@/components/breadcrumbs'
<Breadcrumbs breadcrumbs={[{ label: 'Styles' }]} />
# CSS Modules
TODO
+1 -1
View File
@@ -1 +1 @@
@import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap');