tldraw/apps/examples/src/ExamplePage.tsx

80 lines
2.1 KiB
TypeScript
Raw Normal View History

add descriptions to examples (#2375) Adds descriptions to examples. ![Kapture 2023-12-22 at 17 08 32](https://github.com/tldraw/tldraw/assets/1489520/d78657cf-b3c3-4160-b58b-7c08ed27823d) They show as a list on the index page, and on individual examples they show in a three-js style sidebar. For now, this is disabled completely on mobile. Examples can still be opened in 'standalone' mode to get rid of the sidebar. Note: the 'view code' link won't work until after these changes are merged. There's a small impact on authoring examples: each one needs to live in a folder with a README.md. At a minimum, the readme needs to look like this: ```md --- title: My Example component: ./MyExample.tsx --- Here is a 1-liner about my example ``` Optionally, you can: - Add `hide: true` to the frontmatter to remove the example from the list (you can skip the description this way) - Add `order: 3` to control the order in which the example appears. They're alphabetical otherwise - Add some more description or links to docs below a `---`. This won't show in the listing, but will be visible on GitHub and on the example page itself. As a follow-up, I'd like to add an 'Open in CodeSandbox' link to each example. These won't work until we've made a release with these examples (as our special examples codesandbox is tied to our release process) but the code is there & ready to go! Have a play, let me know what you think! ### Change Type - [x] `documentation` — Changes to the documentation only[^2] --------- Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
2023-12-27 17:17:18 +00:00
import { assert, assertExists } from '@tldraw/tldraw'
import { useEffect, useRef } from 'react'
import { Link } from 'react-router-dom'
import ExamplesTldrawLogo from './components/ExamplesTldrawLogo'
import { ListLink } from './components/ListLink'
import { Example, examples } from './examples'
export function ExamplePage({
example,
children,
}: {
example: Example
children: React.ReactNode
}) {
const scrollElRef = useRef<HTMLUListElement>(null)
const activeElRef = useRef<HTMLLIElement>(null)
const isFirstScroll = useRef(true)
useEffect(() => {
const frame = requestAnimationFrame(() => {
if (activeElRef.current) {
const scrollEl = assertExists(scrollElRef.current)
const activeEl = activeElRef.current
assert(activeEl.offsetParent === scrollEl)
const isScrolledIntoView =
activeEl.offsetTop >= scrollEl.scrollTop &&
activeEl.offsetTop + activeEl.offsetHeight <= scrollEl.scrollTop + scrollEl.offsetHeight
if (!isScrolledIntoView) {
activeEl.scrollIntoView({
behavior: isFirstScroll.current ? 'auto' : 'smooth',
block: isFirstScroll.current ? 'start' : 'center',
})
}
isFirstScroll.current = false
}
})
return () => cancelAnimationFrame(frame)
}, [example])
return (
<div className="example">
<div className="example__info">
<Link className="example__logo" to="/">
<ExamplesTldrawLogo /> examples
</Link>
<ul className="example__info__list scroll-light" ref={scrollElRef}>
{examples
.filter((e) => !e.hide)
.filter((e) => e.order !== null)
.map((e) => (
<ListLink
key={e.path}
ref={e.path === example.path ? activeElRef : undefined}
example={e}
isActive={e.path === example.path}
/>
))}
<li>
<hr />
</li>
{examples
.filter((e) => !e.hide)
.filter((e) => e.order === null)
.map((e) => (
<ListLink
key={e.path}
ref={e.path === example.path ? activeElRef : undefined}
example={e}
isActive={e.path === example.path}
/>
))}
</ul>
</div>
<div className="example__content">{children}</div>
</div>
)
}