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:
parent
a5e6ae87fe
commit
430924f8b6
9 changed files with 97 additions and 44 deletions
|
@ -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>
|
||||
)
|
||||
|
|
|
@ -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 }],
|
||||
],
|
||||
|
|
|
@ -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.
|
||||
|
|
41
apps/docs/components/mdx-components/code.tsx
Normal file
41
apps/docs/components/mdx-components/code.tsx
Normal 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>
|
||||
)
|
||||
}
|
|
@ -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) => {
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue