docs: rework docs site to have different sections (#2686)
This PR starts putting in place the high-level changes we want to make to the docs site. - It makes separate sections for Reference and Examples and Community. - Gets rid of the secondary sidebar and integrates it into the main sidebar. - Groups the reference articles by type. - Pulls in the examples alongside code and a live playground so people don't have to visit examples.tldraw.com separately. <img width="1458" alt="Screenshot 2024-01-30 at 09 43 46" src="https://github.com/tldraw/tldraw/assets/469604/4f5aa339-3a69-4d9b-9b9f-dfdddea623e8"> Again, this is the top-level changes and there's more to be done for the next PR(s): - create quick start page - clean up installation page - add accordion to Examples page prbly - put fun stuff in header (from footer) - landing page - something for landing page of API - search cmd-k and border - cleanup _sidebarReferenceContentLinks - external links _blank - address potential skew issue with code examples - have a link to other examples (next.js, etc.) ### Change Type - [x] `documentation` — Changes to the documentation only[^2] ### Test Plan 1. Make sure examples work! ### Release Notes - Rework our docs site to pull together the examples app and reference section more cohesively. --------- Co-authored-by: Taha <98838967+Taha-Hassan-Git@users.noreply.github.com> Co-authored-by: Steve Ruiz <steveruizok@gmail.com> Co-authored-by: Mitja Bezenšek <mitja.bezensek@gmail.com> Co-authored-by: alex <alex@dytry.ch> Co-authored-by: Lu Wilson <l2wilson94@gmail.com> Co-authored-by: Dan Groshev <git@dgroshev.com>
This commit is contained in:
parent
a43b172b64
commit
3ae48af67c
68 changed files with 94415 additions and 92577 deletions
|
@ -1,65 +1,97 @@
|
|||
'use client'
|
||||
|
||||
import {
|
||||
ArticleHeadings,
|
||||
SidebarContentArticleLink,
|
||||
SidebarContentCategoryLink,
|
||||
SidebarContentLink,
|
||||
SidebarContentList,
|
||||
SidebarContentSectionLink,
|
||||
} from '@/types/content-types'
|
||||
import * as Accordion from '@radix-ui/react-accordion'
|
||||
import Link from 'next/link'
|
||||
import { usePathname } from 'next/navigation'
|
||||
import { createContext, useContext, useEffect } from 'react'
|
||||
import { SectionLinks } from './Header'
|
||||
import { Chevron } from './Icons'
|
||||
import { Search } from './Search'
|
||||
import { SidebarCloseButton } from './SidebarCloseButton'
|
||||
import { ToggleMenuButton } from './ToggleMenuButton'
|
||||
|
||||
type SidebarProps = SidebarContentList
|
||||
|
||||
const activeLinkContext = createContext<string | null>(null)
|
||||
const linkContext = createContext<{
|
||||
activeId: string | null
|
||||
articleId: string | null
|
||||
categoryId: string | null
|
||||
sectionId: string | null
|
||||
} | null>(null)
|
||||
|
||||
export function Sidebar({ links, sectionId, categoryId, articleId }: SidebarProps) {
|
||||
export function Sidebar({
|
||||
headings,
|
||||
links,
|
||||
sectionId,
|
||||
categoryId,
|
||||
articleId,
|
||||
searchQuery,
|
||||
searchType,
|
||||
}: SidebarProps) {
|
||||
const activeId = articleId ?? categoryId ?? sectionId
|
||||
|
||||
const pathName = usePathname()
|
||||
|
||||
useEffect(() => {
|
||||
document.body.classList.remove('sidebar-open')
|
||||
|
||||
document.querySelector('.sidebar [data-active=true]')?.scrollIntoView({ block: 'center' })
|
||||
|
||||
// XXX(mime): scrolling the sidebar into position also scrolls the page to the wrong
|
||||
// spot. this compensates for that but, ugh.
|
||||
document.documentElement.scrollTop = 0
|
||||
}, [pathName])
|
||||
|
||||
return (
|
||||
<>
|
||||
<activeLinkContext.Provider value={activeId}>
|
||||
<linkContext.Provider value={{ activeId, articleId, categoryId, sectionId }}>
|
||||
<div className="sidebar" onScroll={(e) => e.stopPropagation()}>
|
||||
<Search activeId={activeId} />
|
||||
<SidebarLinks links={links} />
|
||||
<Search prevQuery={searchQuery} prevType={searchType} />
|
||||
<div className="sidebar__section__links">
|
||||
<SectionLinks sectionId={sectionId} />
|
||||
</div>
|
||||
<SidebarLinks headings={headings} links={links} />
|
||||
<SidebarCloseButton />
|
||||
</div>
|
||||
<ToggleMenuButton />
|
||||
</activeLinkContext.Provider>
|
||||
</linkContext.Provider>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export function SidebarLinks({ links }: { links: SidebarContentLink[] }) {
|
||||
export function SidebarLinks({
|
||||
headings,
|
||||
links,
|
||||
}: {
|
||||
headings?: ArticleHeadings
|
||||
links: SidebarContentLink[]
|
||||
}) {
|
||||
return (
|
||||
<nav className="sidebar__nav">
|
||||
<ul className="sidebar__list sidebar__sections__list">
|
||||
{links.map((link) => (
|
||||
<SidebarLink key={link.url} {...link} />
|
||||
<SidebarLink key={link.url} headings={headings} {...link} />
|
||||
))}
|
||||
</ul>
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
|
||||
function SidebarLink(props: SidebarContentLink) {
|
||||
function SidebarLink({ headings, ...props }: SidebarContentLink & { headings?: ArticleHeadings }) {
|
||||
switch (props.type) {
|
||||
case 'section': {
|
||||
return <SidebarSection {...props} />
|
||||
return <SidebarSection headings={headings} {...props} />
|
||||
}
|
||||
case 'article': {
|
||||
return <SidebarArticle {...props} />
|
||||
return <SidebarArticle headings={headings} {...props} />
|
||||
}
|
||||
case 'category': {
|
||||
return <SidebarCategory {...props} />
|
||||
|
@ -67,19 +99,19 @@ function SidebarLink(props: SidebarContentLink) {
|
|||
}
|
||||
}
|
||||
|
||||
function SidebarSection({ title, children }: SidebarContentSectionLink) {
|
||||
function SidebarSection({
|
||||
title,
|
||||
children,
|
||||
headings,
|
||||
}: SidebarContentSectionLink & { headings?: ArticleHeadings }) {
|
||||
if (children.length === 0) return null
|
||||
|
||||
return (
|
||||
<li className="sidebar__section">
|
||||
{title && (
|
||||
<Link href={children[0].url} title={title} className="sidebar__section__title">
|
||||
{title}
|
||||
</Link>
|
||||
)}
|
||||
{title && <span className="sidebar__section__title">{title}</span>}
|
||||
<ul className="sidebar__list">
|
||||
{children.map((link) => (
|
||||
<SidebarLink key={link.url} {...link} />
|
||||
<SidebarLink key={link.url} headings={headings} {...link} />
|
||||
))}
|
||||
</ul>
|
||||
</li>
|
||||
|
@ -87,33 +119,102 @@ function SidebarSection({ title, children }: SidebarContentSectionLink) {
|
|||
}
|
||||
|
||||
function SidebarCategory({ title, children }: SidebarContentCategoryLink) {
|
||||
const linkCtx = useContext(linkContext)
|
||||
if (children.length === 0) return null
|
||||
const hasGroups = children.some((child) => !!(child as SidebarContentArticleLink).groupId)
|
||||
const activeArticle = children.find(
|
||||
(child) => (child as SidebarContentArticleLink).articleId === linkCtx?.articleId
|
||||
)
|
||||
const activeGroup = activeArticle && (activeArticle as SidebarContentArticleLink).groupId
|
||||
const groups = ['Class', 'Function', 'Variable', 'Interface', 'Enum', 'TypeAlias', 'Namespace']
|
||||
|
||||
return (
|
||||
<li className="sidebar__category">
|
||||
<Link href={children[0].url} title={title} className="sidebar__link">
|
||||
{title}
|
||||
</Link>
|
||||
<ul className="sidebar__list">
|
||||
{children.map((link) => (
|
||||
<SidebarLink key={link.url} {...link} />
|
||||
))}
|
||||
</ul>
|
||||
{hasGroups ? (
|
||||
<>
|
||||
<span className="sidebar__link">{title}</span>
|
||||
<Accordion.Root
|
||||
type="multiple"
|
||||
defaultValue={[`${linkCtx?.categoryId}-${activeGroup}-${linkCtx?.articleId}`]}
|
||||
>
|
||||
{groups.map((group) => {
|
||||
const articles = children.filter(
|
||||
(child) => (child as SidebarContentArticleLink).groupId === group
|
||||
)
|
||||
if (articles.length === 0) return null
|
||||
|
||||
return (
|
||||
<Accordion.Item
|
||||
key={group}
|
||||
value={`${linkCtx?.categoryId}-${group}-${linkCtx?.articleId}`}
|
||||
>
|
||||
<Accordion.Trigger
|
||||
className="sidebar__section__group__title"
|
||||
style={{ marginLeft: '8px', paddingRight: '8px' }}
|
||||
>
|
||||
{group}
|
||||
<Chevron />
|
||||
</Accordion.Trigger>
|
||||
<Accordion.Content>
|
||||
<ul className="sidebar__list" style={{ paddingLeft: '8px' }}>
|
||||
{articles.map((link) => (
|
||||
<SidebarLink key={link.url} {...link} />
|
||||
))}
|
||||
</ul>
|
||||
</Accordion.Content>
|
||||
</Accordion.Item>
|
||||
)
|
||||
})}
|
||||
</Accordion.Root>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Link href={children[0].url} title={title} className="sidebar__link">
|
||||
{title}
|
||||
</Link>
|
||||
<ul className="sidebar__list">
|
||||
{children.map((link) => (
|
||||
<SidebarLink key={link.url} {...link} />
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
<hr />
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
||||
function SidebarArticle({ title, url, articleId }: SidebarContentArticleLink) {
|
||||
const isActive = useContext(activeLinkContext) === articleId
|
||||
function SidebarArticle({
|
||||
title,
|
||||
url,
|
||||
articleId,
|
||||
headings,
|
||||
}: SidebarContentArticleLink & { headings?: ArticleHeadings }) {
|
||||
const isActive = useContext(linkContext)?.activeId === articleId
|
||||
|
||||
return (
|
||||
<li className="sidebar__article">
|
||||
<Link href={url}>
|
||||
<div className="sidebar__link" data-active={isActive}>
|
||||
{title}
|
||||
</div>
|
||||
<Link href={url} className="sidebar__link" data-active={isActive}>
|
||||
{title}
|
||||
</Link>
|
||||
|
||||
{isActive && (
|
||||
<ul className="sidebar__list">
|
||||
{headings
|
||||
?.filter((heading) => heading.level < 3)
|
||||
.map((heading) => (
|
||||
<li key={heading.slug}>
|
||||
<Link href={`#${heading.slug}`} className="sidebar__link">
|
||||
{heading.isCode ? (
|
||||
<code>{heading.title.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1')}</code>
|
||||
) : (
|
||||
heading.title.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1')
|
||||
)}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue