docs: better code snippets (#2801)

Uses sandpack in all places so we can do richer code snippets.
Also, drive-by fix to fix sidebar logic.
Also, drive-by fix to hide keyboard hint (Cmd+K) for search on mobile.

### Change Type

- [x] `documentation` — Changes to the documentation only[^2]

### Release Notes

- Docs: reworks code snippets
This commit is contained in:
Mime Čuvalo 2024-02-12 14:30:55 +00:00 committed by GitHub
parent a5e6ae87fe
commit 430924f8b6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 97 additions and 44 deletions

View file

@ -1,6 +1,6 @@
'use client'
import { SandpackCodeEditor, SandpackFiles, SandpackProvider } from '@codesandbox/sandpack-react'
import { SandpackCodeViewer, SandpackFiles, SandpackProvider } from '@codesandbox/sandpack-react'
import { useTheme } from 'next-themes'
import { useEffect, useState } from 'react'
@ -43,7 +43,7 @@ export default function ExampleCodeBlock({
}}
theme={theme === 'dark' ? 'dark' : 'light'}
>
<SandpackCodeEditor readOnly />
<SandpackCodeViewer />
</SandpackProvider>
</div>
)

View file

@ -1,8 +1,8 @@
import { MDXRemote } from 'next-mdx-remote/rsc'
import rehypeAutolinkHeadings from 'rehype-autolink-headings'
import rehypeHighlight from 'rehype-highlight'
import rehypeSlug from 'rehype-slug-custom-id'
import { components } from './mdx-components'
// import rehypeHighlight from 'rehype-highlight'
interface MdxProps {
content: string
@ -17,7 +17,7 @@ export function Mdx({ content }: MdxProps) {
mdxOptions: {
// remarkPlugins: [remarkGfm, {}],
rehypePlugins: [
[rehypeHighlight as any, {}],
// [rehypeHighlight as any, {}],
[rehypeAutolinkHeadings, {}],
[rehypeSlug, { enableCustomId: true, maintainCase: true, removeAccents: true }],
],

View file

@ -50,8 +50,8 @@ export function Sidebar({ headings, links, sectionId, categoryId, articleId }: S
const activeLink = document.querySelector('.sidebar__nav [data-active=true]') as HTMLElement
if (
activeLink &&
activeLink.offsetTop < sidebarEl.scrollTop &&
activeLink.offsetTop > sidebarEl.scrollTop + sidebarEl.clientHeight
(activeLink.offsetTop < sidebarEl.scrollTop ||
activeLink.offsetTop > sidebarEl.scrollTop + sidebarEl.clientHeight)
) {
// The above will *mostly* work to keep the position but we have some accordions that will collapse
// (like in the Reference docs) and we need to scroll to the active item.

View file

@ -0,0 +1,41 @@
'use client'
import { SandpackCodeViewer, SandpackFiles, SandpackProvider } from '@codesandbox/sandpack-react'
import { useTheme } from 'next-themes'
export const Code = (props: any) => {
if (!props.className) {
return <code {...props} />
}
const language = props.className.replace('language-', '')
return <CodeBlock code={{ [`App.${language}`]: props.children.trim() }} />
}
export function CodeBlock({ code }: { code: SandpackFiles }) {
const { theme } = useTheme()
const trimmedCode = Object.fromEntries(
Object.entries(code).map(([key, value]) => [key, (value as string).trim()])
)
return (
<div className="code-example">
<SandpackProvider
className="sandpack"
key={`sandpack-${theme}`}
template="react-ts"
options={{ activeFile: Object.keys(code)[0] }}
customSetup={{
dependencies: {
'@tldraw/assets': 'latest',
'@tldraw/tldraw': 'latest',
},
}}
files={trimmedCode}
theme={theme === 'dark' ? 'dark' : 'light'}
>
<SandpackCodeViewer />
</SandpackProvider>
</div>
)
}

View file

@ -1,7 +1,7 @@
/* ---------------------- Lists --------------------- */
import React from 'react'
/* ---------------------- Lists --------------------- */
export const UnorderedList = (props: any) => {
return <ul {...props} />
}
@ -136,11 +136,11 @@ export const Video = (props: any) => {
/* ------------------- Code Blocks ------------------ */
export const Pre = (props: any) => {
return <pre {...props} />
}
if (props.children?.props?.className.startsWith('language-')) {
return props.children
}
export const Code = (props: any) => {
return <code {...props} />
return <pre {...props} />
}
export const Footnotes = (props: any) => {

View file

@ -16,6 +16,7 @@ import {
ListItem,
OrderedList,
Paragraph,
Pre,
Small,
TD,
THead,
@ -25,31 +26,36 @@ import {
Video,
} from './generic'
import { Code, CodeBlock } from './code'
export const components = {
a: A,
blockquote: Blockquote,
code: Code,
h1: Heading1,
h2: Heading2,
h3: Heading3,
h4: Heading4,
h5: Heading5,
h6: Heading6,
blockquote: Blockquote,
hr: Divider,
a: A,
img: Image,
li: ListItem,
ol: OrderedList,
p: Paragraph,
pre: Pre,
table: Table,
td: TD,
thead: THead,
tr: TR,
td: TD,
video: Video,
ol: OrderedList,
ul: UnorderedList,
li: ListItem,
img: Image,
Small: Small,
Image,
Video,
Embed,
video: Video,
ApiHeading,
CodeBlock,
Embed,
Image,
Small: Small,
Video,
...customComponents,
...apiComponents,
}

View file

@ -130,7 +130,7 @@ export default function () {
Sometimes you won't be able to access the store's data synchronously. To handle this case, the `store` property also accepts a [TLStoreWithStatus](?).
```ts
```tsx
export default function () {
const [storeWithStatus, setStoreWithStatus] = useState<TLStoreWithStatus>({
status: 'loading',

View file

@ -12,25 +12,13 @@ At the moment the `@tldraw/tldraw` package is in beta. We also ship a canary ver
First, install the `@tldraw/tldraw` package using `@beta` for the latest beta release.
```bash
yarn add @tldraw/tldraw@beta
```
```bash
npm install @tldraw/tldraw@beta
```
<CodeBlock code={{'yarn': 'yarn add @tldraw/tldraw@beta', 'npm': 'npm install @tldraw/tldraw@beta', 'pnpm': 'pnpm add @tldraw/tldraw@beta'}} />
## Canary
To get the very latest version, use the [latest canary release](https://www.npmjs.com/package/@tldraw/tldraw?activeTab=versions). Docs for the very latest version are also available at [canary.tldraw.dev](https://canary.tldraw.dev).
```bash
yarn add @tldraw/tldraw@canary
```
```bash
npm install @tldraw/tldraw@canary
```
<CodeBlock code={{'yarn': 'yarn add @tldraw/tldraw@canary', 'npm': 'npm install @tldraw/tldraw@canary', 'pnpm': 'pnpm add @tldraw/tldraw@canary'}} />
## Usage
@ -57,7 +45,7 @@ It's important that the [Tldraw](?) component is wrapped in a parent container t
In addition to the [Tldraw](?) component itself, you should also import the `tldraw.css` file from the `@tldraw/tldraw` package.
```ts
```tsx
import '@tldraw/tldraw/tldraw.css'
```
@ -99,7 +87,7 @@ const Tldraw = dynamic(async () => (await import('@tldraw/tldraw')).Tldraw, { ss
If you're using a bundler like webpack or rollup, you can import the assets directly from the `@tldraw/assets` package. Here you can use `getAssetUrlsByMetaUrl` helper function:
```javascript
```tsx
import { getAssetUrlsByMetaUrl } from '@tldraw/assets/urls'
const assetUrls = getAssetUrlsByMetaUrl()
@ -121,7 +109,7 @@ By default we serve these assets from a [public CDN called unpkg](https://unpkg.
If you would like to customize some of the assets you can pass the customizations to our [Tldraw](?) component. For example, to use a custom icon for the `hand` tool you can do the following:
```javascript
```tsx
const assetUrls = {
icons: {
'tool-hand': './custom-tool-hand.svg',
@ -143,7 +131,7 @@ If you want more flexibility you can also host these assets yourself:
You can use our `getAssetUrls` helper function from the `@tldraw/assets` package to generate these urls for you.
```javascript
```tsx
import { getAssetUrls } from '@tldraw/assets/selfHosted'
const assetUrls = getAssetUrls()
@ -155,7 +143,7 @@ While these files must be available, you can overwrite the individual files: for
If you use a CDN for hosting these files you can specify the base url of your assets. To recreate the above option of serving the assets from unpkg you would do the following:
```javascript
```ts
const assetUrls = getAssetUrls({
baseUrl: 'https://unpkg.com/@tldraw/assets@2.0.0-alpha.12/',
})
@ -169,7 +157,7 @@ The [Tldraw](?) component combines two lower-level components: [TldrawEditor](?)
You can customize the appearance of the tldraw editor using the [Tldraw](?) (or [TldrawEditor](?) component's `components` prop.
```ts
```tsx
<Tldraw
components={{
Background: YourCustomBackground,

View file

@ -1210,6 +1210,10 @@ body {
height: auto;
}
.search__keyboard kbd {
display: none;
}
.article {
padding: 24px 16px 16px 16px;
}
@ -1248,7 +1252,9 @@ body {
justify-content: flex-end;
}
}
/* --------------------- Mobile --------------------- */
@media (max-width: 760px) {
.article__image {
margin: 32px -16px;
@ -1325,6 +1331,18 @@ html[data-theme='light'] .hero__dark {
padding: 0px;
}
.code-example .sandpack .sp-syntax-string {
color: var(--sp-syntax-color-definition);
}
.code-example .sandpack .sp-syntax-property {
color: var(--sp-syntax-color-keyword);
}
.code-example .sandpack .sp-syntax-static {
color: var(--sp-syntax-color-keyword);
}
/* ------------------- Hero images ------------------ */
.hero__images {