[docs] Fix links, little style tweaks (#2724)

This PR is a small but mighty improvement to our docs.

### Change Type

- [ ] `patch` — Bug fix
- [ ] `minor` — New feature
- [ ] `major` — Breaking change
- [ ] `dependencies` — Changes to package dependencies[^1]
- [x] `documentation` — Changes to the documentation only[^2]
- [ ] `tests` — Changes to any test code only[^2]
- [ ] `internal` — Any other changes that don't affect the published
package[^2]
- [ ] I don't know

[^1]: publishes a `patch` release, for devDependencies use `internal`
[^2]: will not publish a new version

---------

Co-authored-by: Mime Čuvalo <mimecuvalo@gmail.com>
This commit is contained in:
Steve Ruiz 2024-02-05 14:42:55 +00:00 committed by GitHub
parent 157d24db73
commit dc92e2c61f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 148 additions and 29 deletions

View file

@ -1,5 +1,6 @@
import { ArticleDocsPage } from '@/components/ArticleDocsPage' import { ArticleDocsPage } from '@/components/ArticleDocsPage'
import { CategoryDocsPage } from '@/components/CategoryDocsPage' import { CategoryDocsPage } from '@/components/CategoryDocsPage'
import { ExampleDocsPage } from '@/components/ExampleDocsPage'
import { SectionDocsPage } from '@/components/SectionDocsPage' import { SectionDocsPage } from '@/components/SectionDocsPage'
import { getDb } from '@/utils/ContentDatabase' import { getDb } from '@/utils/ContentDatabase'
import { Metadata } from 'next' import { Metadata } from 'next'
@ -110,6 +111,9 @@ export default async function ContentPage({ params }: { params: { id: string | s
return <CategoryDocsPage category={content.category} /> return <CategoryDocsPage category={content.category} />
} }
case 'article': { case 'article': {
if (content.article.componentCode) {
return <ExampleDocsPage article={content.article} />
}
return <ArticleDocsPage article={content.article} /> return <ArticleDocsPage article={content.article} />
} }
default: { default: {

View file

@ -3,7 +3,6 @@ import { getDb } from '@/utils/ContentDatabase'
import { ArticleDetails } from './ArticleDetails' import { ArticleDetails } from './ArticleDetails'
import { ArticleNavLinks } from './ArticleNavLinks' import { ArticleNavLinks } from './ArticleNavLinks'
import { Breadcrumb } from './Breadcrumb' import { Breadcrumb } from './Breadcrumb'
import ExampleCodeBlock from './ExampleCodeBlock'
import { Header } from './Header' import { Header } from './Header'
import { Mdx } from './Mdx' import { Mdx } from './Mdx'
import { Sidebar } from './Sidebar' import { Sidebar } from './Sidebar'
@ -27,25 +26,13 @@ export async function ArticleDocsPage({ article }: { article: Article }) {
<> <>
<Header sectionId={section.id} /> <Header sectionId={section.id} />
<Sidebar headings={headings} {...sidebar} /> <Sidebar headings={headings} {...sidebar} />
<main <main className={`article${isGenerated ? ' article__api-docs' : ''}`}>
className={`article${isGenerated ? ' article__api-docs' : ''}${article.componentCode ? ' article__example' : ''}`}
>
<div className="page-header"> <div className="page-header">
<Breadcrumb section={section} category={category} /> <Breadcrumb section={section} category={category} />
<h1>{article.title}</h1> <h1>{article.title}</h1>
</div> </div>
{article.hero && <Image alt="hero" title={article.title} src={`images/${article.hero}`} />} {article.hero && <Image alt="hero" title={article.title} src={`images/${article.hero}`} />}
{article.content && <Mdx content={article.content} />} {article.content && <Mdx content={article.content} />}
{article.componentCode && (
<ExampleCodeBlock
articleId={article.id}
files={{
'App.tsx': article.componentCode,
...(article.componentCodeFiles ? JSON.parse(article.componentCodeFiles) : null),
}}
activeFile={'App.tsx'}
/>
)}
{isGenerated ? null : <ArticleDetails article={article} />} {isGenerated ? null : <ArticleDetails article={article} />}
{links && <ArticleNavLinks links={links} />} {links && <ArticleNavLinks links={links} />}
</main> </main>

View file

@ -25,12 +25,10 @@ export default function ExampleCodeBlock({
} }
return ( return (
<> <div className="code-example">
<iframe <iframe src={`${SERVER}/${articleId}/full`} />
src={`${SERVER}/${articleId}/full`}
style={{ border: 0, height: '50vh', width: '100%' }}
/>
<SandpackProvider <SandpackProvider
className="sandpack"
key={`sandpack-${theme}-${activeFile}`} key={`sandpack-${theme}-${activeFile}`}
template="react-ts" template="react-ts"
options={{ activeFile }} options={{ activeFile }}
@ -47,6 +45,6 @@ export default function ExampleCodeBlock({
> >
<SandpackCodeEditor readOnly /> <SandpackCodeEditor readOnly />
</SandpackProvider> </SandpackProvider>
</> </div>
) )
} }

View file

@ -0,0 +1,49 @@
import { Article } from '@/types/content-types'
import { getDb } from '@/utils/ContentDatabase'
import { ArticleNavLinks } from './ArticleNavLinks'
import { Breadcrumb } from './Breadcrumb'
import ExampleCodeBlock from './ExampleCodeBlock'
import { Header } from './Header'
import { Mdx } from './Mdx'
import { Sidebar } from './Sidebar'
import { Image } from './mdx-components/generic'
export async function ExampleDocsPage({ article }: { article: Article }) {
const db = await getDb()
const section = await db.getSection(article.sectionId)
const category = await db.getCategory(article.categoryId)
const headings = await db.getArticleHeadings(article.id)
const links = await db.getArticleLinks(article)
const sidebar = await db.getSidebarContentList({
sectionId: section.id,
categoryId: category.id,
articleId: article.id,
})
return (
<>
<Header sectionId={section.id} />
<Sidebar headings={headings} {...sidebar} />
<main className={`article article__example`}>
<div className="page-header">
<Breadcrumb section={section} category={category} />
<h1>{article.title}</h1>
</div>
{article.hero && <Image alt="hero" title={article.title} src={`images/${article.hero}`} />}
{article.description && <Mdx content={article.description} />}
{article.componentCode && (
<ExampleCodeBlock
articleId={article.id}
files={{
'App.tsx': article.componentCode,
...(article.componentCodeFiles ? JSON.parse(article.componentCodeFiles) : null),
}}
activeFile={'App.tsx'}
/>
)}
{article.content && <Mdx content={article.content} />}
{links && <ArticleNavLinks links={links} />}
</main>
</>
)
}

View file

@ -22,11 +22,19 @@ export function Header({ sectionId }: { sectionId?: string }) {
<Search /> <Search />
<div className="layout__header__sections_and_socials"> <div className="layout__header__sections_and_socials">
<SectionLinks sectionId={sectionId} /> <SectionLinks sectionId={sectionId} />
<ThemeSwitcher /> <a
href="https://x.com/tldraw/"
className="sidebar__button icon-button"
title="twitter"
target="_blank"
>
<Icon icon="twitter" />
</a>
<a <a
href="https://discord.com/invite/SBBEVCA4PG" href="https://discord.com/invite/SBBEVCA4PG"
className="sidebar__button icon-button" className="sidebar__button icon-button"
title="discord" title="discord"
target="_blank"
> >
<Icon icon="discord" /> <Icon icon="discord" />
</a> </a>
@ -34,9 +42,11 @@ export function Header({ sectionId }: { sectionId?: string }) {
href="https://github.com/tldraw/tldraw" href="https://github.com/tldraw/tldraw"
className="sidebar__button icon-button" className="sidebar__button icon-button"
title="github" title="github"
target="_blank"
> >
<Icon icon="github" /> <Icon icon="github" />
</a> </a>
<ThemeSwitcher />
</div> </div>
</div> </div>
) )
@ -62,7 +72,7 @@ export function SectionLinks({ sectionId }: { sectionId?: string | null }) {
Reference Reference
</a> </a>
<a <a
href="/examples/basic/develop" href="/examples/basic/basic"
title="Examples" title="Examples"
data-active={sectionId === 'examples'} data-active={sectionId === 'examples'}
className="layout_header__section" className="layout_header__section"

View file

@ -42,7 +42,7 @@ export function Sidebar({ headings, links, sectionId, categoryId, articleId }: S
return ( return (
<> <>
<linkContext.Provider value={{ activeId, articleId, categoryId, sectionId }}> <linkContext.Provider value={{ activeId, articleId, categoryId, sectionId }}>
<div className="sidebar" onScroll={(e) => e.stopPropagation()}> <div className="sidebar scroll-light" onScroll={(e) => e.stopPropagation()}>
<Search /> <Search />
<div className="sidebar__section__links"> <div className="sidebar__section__links">
<SectionLinks sectionId={sectionId} /> <SectionLinks sectionId={sectionId} />
@ -125,7 +125,7 @@ function SidebarCategory({
<li className="sidebar__category"> <li className="sidebar__category">
{hasGroups ? ( {hasGroups ? (
<> <>
<span className="sidebar__link">{title}</span> <span className="sidebar__link sidebar__category__title">{title}</span>
<Accordion.Root <Accordion.Root
type="multiple" type="multiple"
defaultValue={[`${linkCtx?.categoryId}-${activeGroup}-${linkCtx?.articleId}`]} defaultValue={[`${linkCtx?.categoryId}-${activeGroup}-${linkCtx?.articleId}`]}
@ -162,7 +162,11 @@ function SidebarCategory({
</> </>
) : ( ) : (
<> <>
<Link href={children[0].url} title={title} className="sidebar__link"> <Link
href={children[0].url}
title={title}
className="sidebar__link sidebar__category__title"
>
{title} {title}
</Link> </Link>
<ul className="sidebar__list"> <ul className="sidebar__list">

View file

@ -119,6 +119,13 @@ export function generateSection(section: InputSection, articles: Articles, index
: `/${section.id}/${categoryId}/${articleId}`, : `/${section.id}/${categoryId}/${articleId}`,
} }
if (isExamples) {
// split content above the first ---
const splitUp = parsed.content.split('---\n')
article.description = splitUp[0]
article.content = splitUp.slice(1).join('---\n')
}
if (isIndex) { if (isIndex) {
article.categoryIndex = -1 article.categoryIndex = -1
article.sectionIndex = -1 article.sectionIndex = -1

View file

@ -471,10 +471,6 @@ body {
overflow-x: auto; overflow-x: auto;
} }
.article.article__example pre {
margin: 0px;
}
.article__api-docs pre { .article__api-docs pre {
margin: 24px 0px; margin: 24px 0px;
} }
@ -959,6 +955,12 @@ body {
box-shadow: var(--shadow-small); box-shadow: var(--shadow-small);
} }
.sidebar__category__title {
font-size: 14px;
}
/* --------------------- Search --------------------- */
.sidebar .search__wrapper { .sidebar .search__wrapper {
display: none; display: none;
} }
@ -1235,6 +1237,33 @@ html[data-theme='light'] .hero__dark {
display: none; display: none;
} }
/* ------------------ Code Example ------------------ */
.code-example iframe {
border: 0;
min-height: 500px;
height: 50vh;
width: 100%;
}
.code-example .sandpack {
margin-bottom: 32px;
}
.code-example .sandpack {
border-radius: 6px;
padding: 0px;
border: 1px solid var(--color-tint-3);
border-radius: 6px;
overflow: hidden;
}
.code-example .sandpack pre {
background-color: transparent;
margin: 0px;
padding: 0px;
}
/* ------------------- Hero images ------------------ */ /* ------------------- Hero images ------------------ */
.hero__images { .hero__images {
@ -1344,3 +1373,34 @@ html[data-theme='light'] .hero__dark {
[data-state='open'] > .CaretDown { [data-state='open'] > .CaretDown {
transform: rotate(-180deg); transform: rotate(-180deg);
} }
/* --------------------- Scroll --------------------- */
.scroll-light {
scrollbar-width: thin;
}
.scroll-light::-webkit-scrollbar {
display: block;
width: 8px;
height: 8px;
position: absolute;
top: 0;
left: 0;
background-color: inherit;
}
.scroll-light::-webkit-scrollbar-button {
display: none;
width: 0;
height: 10px;
}
.scroll-light::-webkit-scrollbar-thumb {
background-clip: padding-box;
width: 0;
min-height: 36px;
border: 2px solid transparent;
border-radius: 6px;
background-color: rgba(0, 0, 0, 0.25);
}
.scroll-light::-webkit-scrollbar-thumb:hover {
background-color: rgba(144, 144, 144);
}