Skip to content

Commit 80f9823

Browse files
authored
Split API page (#191)
* Split API page * Update API index * Update API reference * Group APIs * Make API open by default * Remove oder attribute * Add features
1 parent d9c3310 commit 80f9823

23 files changed

+516
-293
lines changed

app/Sidebar.js

Lines changed: 70 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,60 @@
22
import Link from "next/link";
33
import {usePathname} from "next/navigation";
44
import {cn} from "./cn.js";
5+
import {useState} from "react";
6+
import {ChevronRight} from "lucide-react";
57

6-
export function Sidebar({docs, onLinkClick}) {
8+
function NavItem({doc, isActive, onClick}) {
9+
return (
10+
<Link
11+
href={`/docs/${doc.slug}`}
12+
className={cn("block px-3 py-2 rounded-md hover:bg-gray-100", isActive(doc.slug) && "bg-gray-100")}
13+
onClick={onClick}
14+
>
15+
<li>{doc.title}</li>
16+
</Link>
17+
);
18+
}
19+
20+
function NavGroup({group, docsMap, isActive, onClick}) {
21+
const pathname = usePathname();
22+
const isGroupActive = group.slug === pathname.split("/docs/")[1] || group.items.some((item) => isActive(item.slug));
23+
const [isOpen, setIsOpen] = useState(true);
24+
25+
return (
26+
<div>
27+
<div className={cn(isActive(group.slug) && "bg-gray-100", "flex items-center rounded-md hover:bg-gray-100")}>
28+
{group.slug ? (
29+
<Link href={`/docs/${group.slug}`} className={cn("flex-1 px-3 py-2")} onClick={onClick}>
30+
<span className="font-medium">{group.title}</span>
31+
</Link>
32+
) : (
33+
<span className="font-medium cursor-pointer px-3 py-2 flex-1" onClick={() => setIsOpen(!isOpen)}>
34+
{group.title}
35+
</span>
36+
)}
37+
<button
38+
onClick={() => setIsOpen(!isOpen)}
39+
className={cn("px-2 py-2 ")}
40+
aria-label={isOpen ? "Collapse section" : "Expand section"}
41+
>
42+
<ChevronRight className={cn("w-4 h-4 transition-transform", isOpen && "rotate-90")} />
43+
</button>
44+
</div>
45+
{isOpen && (
46+
<ul className="ml-4">
47+
{group.items.map((item) => {
48+
const doc = docsMap[item.slug];
49+
if (!doc) return null;
50+
return <NavItem key={doc.slug} doc={doc} isActive={isActive} onClick={onClick} />;
51+
})}
52+
</ul>
53+
)}
54+
</div>
55+
);
56+
}
57+
58+
export function Sidebar({navStructure, docsMap, onLinkClick}) {
759
const pathname = usePathname();
860
const isActive = (slug) => pathname.startsWith(`/docs/${slug}`);
961
const handleLinkClick = () => {
@@ -13,18 +65,23 @@ export function Sidebar({docs, onLinkClick}) {
1365
};
1466
return (
1567
<ul className={cn("h-full", "overflow-auto px-4 w-full")}>
16-
{docs
17-
.sort((a, b) => a.order - b.order)
18-
.map((doc) => (
19-
<Link
20-
href={`/docs/${doc.slug}`}
21-
key={doc.title}
22-
className={cn("block px-3 py-2 rounded-md hover:bg-gray-100", isActive(doc.slug) && "bg-gray-100")}
23-
onClick={handleLinkClick}
24-
>
25-
<li>{doc.title}</li>
26-
</Link>
27-
))}
68+
{navStructure.map((item) => {
69+
if (item.type === "group") {
70+
return (
71+
<NavGroup
72+
key={item.slug || item.title}
73+
group={item}
74+
docsMap={docsMap}
75+
isActive={isActive}
76+
onClick={handleLinkClick}
77+
/>
78+
);
79+
} else {
80+
const doc = docsMap[item.slug];
81+
if (!doc) return null;
82+
return <NavItem key={doc.slug} doc={doc} isActive={isActive} onClick={handleLinkClick} />;
83+
}
84+
})}
2885
</ul>
2986
);
3087
}

app/docs/DocsLayoutClient.jsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {cn} from "../cn.js";
44
import {useState, useEffect, useRef} from "react";
55
import {TableOfContents} from "lucide-react";
66

7-
export function DocsLayoutClient({docs, children}) {
7+
export function DocsLayoutClient({navStructure, docsMap, children}) {
88
const [overlayOpen, setOverlayOpen] = useState(false);
99
const overlayRef = useRef(null);
1010

@@ -32,7 +32,7 @@ export function DocsLayoutClient({docs, children}) {
3232
<div className={cn("flex", "h-[calc(100vh-65px)] overflow-auto")}>
3333
<div className={cn("hidden md:block")}>
3434
<div style={{width: "320px"}} className={cn("pt-4 h-full")}>
35-
<Sidebar docs={docs} />
35+
<Sidebar navStructure={navStructure} docsMap={docsMap} />
3636
</div>
3737
</div>
3838
<div className={cn("flex-1", "overflow-auto relative")}>
@@ -54,7 +54,7 @@ export function DocsLayoutClient({docs, children}) {
5454
<div className={cn("absolute inset-0 bg-black bg-opacity-50")} />
5555
<div ref={overlayRef} className={cn("absolute left-0 top-0 h-full w-80 bg-white shadow-xl overflow-auto")}>
5656
<div className={cn("pt-4")}>
57-
<Sidebar docs={docs} onLinkClick={() => setOverlayOpen(false)} />
57+
<Sidebar navStructure={navStructure} docsMap={docsMap} onLinkClick={() => setOverlayOpen(false)} />
5858
</div>
5959
</div>
6060
</div>

app/docs/animations-authoring.recho.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
/**
22
* @title Animations Authoring
3-
* @order 5
43
*/
54

65
/**

app/docs/api-echo-clear.recho.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* @title echo.clear()
3+
*/
4+
5+
/**
6+
* ============================================================================
7+
* = echo.clear() =
8+
* ============================================================================
9+
*
10+
* Clear the output of the current block.
11+
*
12+
* @returns {void}
13+
*/
14+
15+
{
16+
echo("Hello, World!");
17+
setTimeout(() => echo.clear(), 1000);
18+
}
19+

app/docs/api-echo.recho.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/**
2+
* @title echo(...values)
3+
*/
4+
5+
/**
6+
* ============================================================================
7+
* = echo(...values) =
8+
* ============================================================================
9+
*
10+
* Echos one or more values inline with your code as comments. If only one
11+
* value is provided, return the value itself. If multiple values are provided,
12+
* return all the values as an array.
13+
*
14+
* @param {...any} values - The values to echo.
15+
* @returns {any} The values if multiple values are provided, or the single value.
16+
*/
17+
18+
//➜ "Hello, World!"
19+
echo("Hello, World!");
20+
21+
//➜ 1 2 3
22+
echo(1, 2, 3);
23+
24+
//➜ Peter: Age = 20
25+
//➜ Height = 180
26+
echo("Peter: ", "Age = 20\nHeight = 180");
27+
28+
const a = echo(1 + 2);
29+
30+
//➜ 3
31+
echo(a);
32+
33+
const numbers = echo(1, 2, 3);
34+
35+
//➜ [ 1, 2, 3 ]
36+
echo(numbers);
37+

app/docs/api-inspect.recho.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* @title recho.inspect(value[, options])
3+
*/
4+
5+
/**
6+
* ============================================================================
7+
* = recho.inspect(value[, options]) =
8+
* ============================================================================
9+
*
10+
* Formats a value for inspection with customizable options.
11+
*
12+
* @param {any} value - The value to inspect.
13+
* @param {Object} [options] - The options to format the output.
14+
* @param {string} [options.quote="double"] - The quote style of the output ("single", "double", or false).
15+
* @param {number} [options.indent=null] - The indentation of the output (null, "\t", or a positive integer).
16+
* @param {number} [options.limit=200] - The character limit of the output.
17+
* @returns {string} The formatted string representation of the value.
18+
*/
19+
20+
//➜ "Hello, World!"
21+
const defaultQuotedString = echo("Hello, World!");
22+
23+
//➜ 'Hello, World!'
24+
const singleQuotedString = echo(recho.inspect("Hello, World!", {quote: "single"}));
25+
26+
//➜ "Hello, World!"
27+
const doubleQuotedString = echo(recho.inspect("Hello, World!", {quote: "double"}));
28+
29+
//➜ Hello, World!
30+
const unquotedString = echo(recho.inspect("Hello, World!", {quote: false}));
31+
32+
//➜ {
33+
//➜ a: 1,
34+
//➜ b: 2,
35+
//➜ c: 3
36+
//➜ }
37+
const indentedObject = echo(recho.inspect({a: 1, b: 2, c: 3}, {indent: 2}));
38+
39+
//➜ [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
40+
const array1000 = echo(recho.inspect(new Array(1000).fill(0), {limit: Infinity}));
41+

app/docs/api-interval.recho.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* @title recho.interval(milliseconds)
3+
*/
4+
5+
/**
6+
* ============================================================================
7+
* = recho.interval(milliseconds) =
8+
* ============================================================================
9+
*
10+
* Returns a generator that yields values at a specified interval.
11+
*
12+
* @param {number} milliseconds - The interval in milliseconds.
13+
* @returns {Generator<number>}
14+
*/
15+
16+
const interval = recho.interval(1000);
17+
18+
//➜ 1
19+
echo(interval);
20+

app/docs/api-invalidation.recho.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/**
2+
* @title invalidation()
3+
*/
4+
5+
/**
6+
* ============================================================================
7+
* = invalidation() =
8+
* ============================================================================
9+
*
10+
* Returns a promise that resolves before re-running the current block.
11+
*
12+
* @returns {Promise<void>}
13+
*/
14+
15+
//➜ 9
16+
{
17+
let count = echo(10);
18+
19+
const timer = setInterval(() => {
20+
if (count-- <= 0) clearInterval(timer);
21+
else {
22+
echo.clear();
23+
echo(count);
24+
}
25+
}, 1000);
26+
27+
invalidation.then(() => clearInterval(timer));
28+
}
29+

app/docs/api-now.recho.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* @title recho.now()
3+
*/
4+
5+
/**
6+
* ============================================================================
7+
* = recho.now() =
8+
* ============================================================================
9+
*
10+
* Returns a generator that yields the current time continuously.
11+
*
12+
* @returns {Generator<number>}
13+
*/
14+
15+
const now = recho.now();
16+
17+
//➜ 1757422825350
18+
echo(now);
19+

app/docs/api-number.recho.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/**
2+
* @title recho.number(value[, options])
3+
*/
4+
5+
/**
6+
* ============================================================================
7+
* = recho.number(value[, options]) =
8+
* ============================================================================
9+
*
10+
* Creates an interactive number input control that returns a constrained number.
11+
* In the editor, this renders as increment and decrement buttons around the
12+
* number value.
13+
*
14+
* @param {number} value - The initial number value.
15+
* @param {Object} [options] - The options to constrain the number.
16+
* @param {number} [options.min=-Infinity] - The minimum allowed value.
17+
* @param {number} [options.max=Infinity] - The maximum allowed value.
18+
* @param {number} [options.step=1] - The step size for increment/decrement operations.
19+
* @returns {number} The number value, constrained to the specified range.
20+
*/
21+
22+
const count = recho.number(5);
23+
24+
const volume = recho.number(5.5, {min: 0, max: 10, step: 0.1});
25+
26+
//➜ "Volume ▓▓▓▓▓▒▒▒▒▒ 55%"
27+
{
28+
const filled = "▓".repeat(Math.floor(volume));
29+
const empty = "▒".repeat(Math.ceil(10 - volume));
30+
echo(`Volume ${filled}${empty} ${volume * 10}%`);
31+
}
32+
33+
const signal = recho.number(0b1010101010101010, {min: 0, max: 0xffff});
34+
35+
//➜ ╶┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐
36+
//➜ └┘└┘└┘└┘└┘└┘└┘└
37+
{
38+
let upper = "";
39+
let lower = "";
40+
let lastBit = null;
41+
for (const bit of signal.toString(2)) {
42+
if (lastBit === null) {
43+
upper += bit == "1" ? "╶" : " ";
44+
lower += bit == "1" ? " " : "╶";
45+
} else if (lastBit === bit) {
46+
upper += bit == "1" ? "─" : " ";
47+
lower += bit == "1" ? " " : "─";
48+
} else {
49+
upper += bit == "1" ? "┌" : "┐";
50+
lower += bit == "1" ? "┘" : "└";
51+
}
52+
lastBit = bit;
53+
}
54+
echo(upper + "\n" + lower);
55+
}
56+
57+
const temperature = recho.number(24, {min: -10, max: 40, step: 0.5});
58+
59+
//➜ "The room temperature is 24 °C (75.2 °F)."
60+
{
61+
const fahrenheit = (temperature * 9) / 5 + 32;
62+
echo(`The room temperature is ${temperature} °C (${fahrenheit} °F).`);
63+
}
64+

0 commit comments

Comments
 (0)