Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add API reference page #460

Merged
merged 1 commit into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/web/app/docs/[[...slug]]/preview-implementation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { z } from "zod"
import { Demo } from "@/components/demo"
import { Pre, RawCode, highlight } from "codehike/code"
import { CopyButton } from "@/components/copy-button"
import { ComponentPackLink } from "@/components/component-pack-link"

const ContentSchema = Block.extend({
demo: Block,
Expand Down
20 changes: 20 additions & 0 deletions apps/web/components/component-pack-link.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { ArrowRight } from "lucide-react"

export function ComponentPackLink() {
return (
<div className="border border-pink-500 rounded-lg p-5 my-6 bg-zinc-800">
Don't have time to build it yourself? Get a documentation component
library customized for your tech stack and design system.
<button className="bg-pink-500 text-white rounded-lg px-4 py-1 mt-2 block">
Get the Docs Kit{" "}
<span
className="text-xs ml-2 line-through"
style={{ textDecorationThickness: "2px" }}
>
60% off
</span>{" "}
<ArrowRight size={20} className="inline-block" />
</button>
</div>
)
}
8 changes: 7 additions & 1 deletion apps/web/content/blog/content-presentation-gap.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@ authors: [pomber]
draft: true
---

import { Demo } from "./content-presentation-gap"

Notice: content means Markdown, presentation means UI components. So, another title could be "The Markdown-React gap".

Let's tart with an example.

> demo (roman emperors)
<Demo />

This is a UI pattern commonly referred as scrollytelling, where the content is presented in a way that is tightly coupled with the user's scroll position.

Expand All @@ -19,6 +23,8 @@ It's also used for technical content like [Stripe's API reference](https://strip
A component to implement this pattern is not super hard to build, usually it's a combination of an intersection observer and position sticky.

```tsx
import { useEffect, useRef, useState } from "react"

type Props = {
steps: {
content: React.ReactNode
Expand Down
100 changes: 100 additions & 0 deletions apps/web/content/blog/content-presentation-gap.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
"use client"

import { useEffect, useRef, useState } from "react"

export function Demo() {
return (
<div className="border">
<Scrollytelling
steps={[
{
content: (
<div>
<h1>Augustus</h1>
<p>
Augustus was the first Roman emperor, reigning from 27 BC
until his death in AD 14.
</p>
</div>
),
sticker: (
<img src="/blog/build-time-components.png" alt="Augustus" />
),
},
{
content: (
<div>
<h1>Nero</h1>
<p>
Nero was the last Roman emperor of the Julio-Claudian dynasty.
</p>
</div>
),
sticker: <img src="/blog/v1.png" alt="Nero" />,
},
{
content: (
<div>
<h1>Trajan</h1>
<p>Trajan was Roman emperor from 98 to 117.</p>
</div>
),
sticker: <img src="/blog/fine-grained-markdown.png" alt="Trajan" />,
},
]}
/>
</div>
)
}

type Props = {
steps: {
content: React.ReactNode
sticker: React.ReactNode
}[]
}
function Scrollytelling({ steps }: Props) {
const [currentStep, setCurrentStep] = useState(0)
const ref = useRef<HTMLDivElement>(null)

useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setCurrentStep(parseInt(entry.target.id))
}
},
{
rootMargin: "-48% 0px",
threshold: 0.01,
root: ref.current,
},
)

steps.forEach((_, i) => {
observer.observe(document.getElementById(i.toString())!)
})

return () => observer.disconnect()
}, [])

return (
<div ref={ref} className="flex max-h-64 overflow-auto relative p-4">
<div>
{steps.map((step, i) => (
<div
key={i}
id={i.toString()}
style={{ opacity: i === currentStep ? 1 : 0.2 }}
>
{step.content}
</div>
))}
<div style={{ height: 48 }} />
</div>
<div style={{ position: "sticky", top: 0 }}>
{steps[currentStep].sticker}
</div>
</div>
)
}
6 changes: 2 additions & 4 deletions apps/web/content/blog/the-curse-of-markdown.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ Tradeoffs: https://youtu.be/zqhE-CepH2g?si=7iYgDUjAhJNVmYJN&t=446

examples of websites that mdx allow:

- josh's blog
- react docs
- interactive blogs
- interactive docs

---

Expand All @@ -36,5 +36,3 @@ Examples are:

- stripe
- swiftui
- nanda
- pudding
213 changes: 213 additions & 0 deletions apps/web/content/docs/api.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
---
title: API Reference
description: Comprehensive list of codehike's API
---

import { Usage } from "./api"

## `codehike/mdx`

```tsx
import { remarkCodeHike, recmaCodeHike } from "codehike/mdx"
```

### `remarkCodeHike`

A remark plugin that transform codeblocks and inline code into the specified components.

- from annotation
- you have to provide the components

```tsx
import { remarkCodeHike, recmaCodeHike } from "codehike/mdx"

/** @type {import('codehike/mdx').CodeHikeConfig} */
const chConfig = {
components: { code: "MyCode", inlineCode: "MyInlineCode" },
ignoreCode: (codeblock) => codeblock.lang === "mermaid",
syntaxHighlighting: { theme: "github-dark" },
}

// what you do with the `mdxOptions` depends on what you use to handle mdx
const mdxOptions = {
remarkPlugins: [[remarkCodeHike, chConfig], ...otherRemarkPlugins],
recmaPlugins: [[recmaCodeHike, chConfig]],
}
```

#### `CodeHikeConfig.components.code`

If you specify a component for `code`, the `remarkCodeHike` plugin will replace code blocks with that component. The language, meta, and value of the code block will be passed inside a `codeblock` prop.

<Usage>

## !caption

How `remarkCodeHike` compiles codeblocks using the `code` component

## !left

```tsx your-config.js
const chConfig = {
// !mark[/MyCode/] 1
components: { code: "MyCode" },
}
```

{/* prettier-ignore */}
````mdx content.mdx
# Hello

{/* !mark[/js|lorem ipsum|console.log\(1\)/gm] 5 */}
```js lorem ipsum
console.log(1)
```
````

## !right

{/* prettier-ignore */}
```jsx compiled output -w
export default function Content(props = {}) {
// !mark[/MyCode/gm] 1
// !mark[/js|lorem ipsum|console.log\(1\)/gm] 5
const { MyCode } = props.components
return (
<>
<h1>Hello</h1>
<MyCode codeblock={{
lang: "js",
meta: "lorem ipsum",
value: "console.log(1)"
}} />
</>
)
}
```

</Usage>

FAQ

- how to pass the components to the `Content` component?
- how to syntax highlight the code?

#### `CodeHikeConfig.components.inlineCode`

If you specify a component for `inlineCode`, the `remarkCodeHike` plugin will replace inline code with that component. The value of the inline code will be passed inside a `codeblock` prop.

Code Hike uses a special syntax to define inline code ``_`code`_``. This syntax also allows you to specify the language and meta for inline code ``_py lorem ipsum`print 5`_``, will give you _`{lang: "py", meta: "lorem ipsum", value: "print 5"}`_.

<Usage>

## !caption

How `remarkCodeHike` compiles inline code using the `inlineCode` component

## !left

```tsx your-config.js
const chConfig = {
// !mark[/MyInlineCode/] 1
components: { inlineCode: "MyInlineCode" },
}
```

{/* prettier-ignore */}
````mdx content.mdx -w
# Hello

Case 1: `var x = 10`

Case 2: _`var x = 10`_

Case 3: _css`a { color: #123 }`_
````

## !right

{/* prettier-ignore */}
```jsx compiled output -w
export default function Content(props = {}) {
// !mark[/MyInlineCode/gm] 1
const { MyInlineCode } = props.components
return (
<>
<h1>Hello</h1>
<p>Case 1: <code>var x = 10</code></p>
<p>Case 2:
<MyInlineCode codeblock={{
lang: "jsx",
value: "var x = 10"
}} />
</p>
<p>Case 3:
<MyInlineCode codeblock={{
lang: "css",
value: "a { color: #123 }"
}} />
</p>
</>
)
}
```

</Usage>

#### `CodeHikeConfig.ignoreCode`

#### `CodeHikeConfig.syntaxHighlighting`

### `recmaCodeHike`

A recma plugin that parses code hike blocks.

## `codehike`

```tsx
import { parse } from "codehike"
```

## `codehike/blocks`

```tsx
import {
parseRoot,
parseProps,
Block,
CodeBlock,
HighlightedCodeBlock,
ImageBlock,
} from "codehike/blocks"
```

## `codehike/code`

```tsx
import {
highlight,
Pre,
Inline,
InnerPre,
InnerLine,
InnerToken,
getPreRef,
} from "codehike/code"
```

## `codehike/utils`

```tsx
import {
SelectionProvider,
Selectable,
Selection,
useSelectedIndex,
} from "codehike/utils/selection"

import {
TokenTransitionsSnapshot,
calculateTransitions,
getStartingSnapshot,
} from "codehike/utils/token-transitions"
```
Loading