T48a Docs · Frame: a Docs tab, /docs/ and /docs/$page/, Markdown guides with a rail, an on-this-page list, previous and next and code blocks; full Rust samples are compiled examples shown as text
This commit is contained in:
1 parent
157176e2fb
commit
fba90c22e6
12 files changed
+305
-6
No files matched your search
@@ -0,0 +1,67 @@
|
||||
import { Marked, type Tokens } from "marked";
|
||||
|
||||
const sources = import.meta.glob<string>("./*.md", { query: "?raw", import: "default", eager: true });
|
||||
const examples = import.meta.glob<string>("../../../examples/docs/*.rs", { query: "?raw", import: "default", eager: true });
|
||||
|
||||
/** The guides in reading order, by file name. */
|
||||
const ORDER = ["introduction"];
|
||||
|
||||
export interface Guide {
|
||||
/** The path segment; the introduction has none. */
|
||||
slug: string;
|
||||
title: string;
|
||||
html: string;
|
||||
/** The `##` headings, for the on-this-page list. */
|
||||
toc: { id: string; text: string }[];
|
||||
}
|
||||
|
||||
const escape = (text: string) => text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
||||
|
||||
const slugify = (text: string) =>
|
||||
text
|
||||
.toLowerCase()
|
||||
.replace(/<[^>]+>/g, "")
|
||||
.replace(/[^a-z0-9]+/g, "-")
|
||||
.replace(/^-|-$/g, "");
|
||||
|
||||
function read(file: string): Guide {
|
||||
const source = sources[`./${file}.md`];
|
||||
if (source === undefined) throw new Error(`docs: no ${file}.md`);
|
||||
let title = "";
|
||||
const toc: Guide["toc"] = [];
|
||||
const marked = new Marked({
|
||||
renderer: {
|
||||
heading({ tokens, depth }: Tokens.Heading) {
|
||||
const html = this.parser.parseInline(tokens);
|
||||
if (depth === 1) {
|
||||
title = html.replace(/<[^>]+>/g, "");
|
||||
return "";
|
||||
}
|
||||
const id = slugify(html);
|
||||
if (depth === 2) {
|
||||
if (toc.some((h) => h.id === id)) throw new Error(`docs: ${file}.md repeats heading ${id}`);
|
||||
toc.push({ id, text: html.replace(/<[^>]+>/g, "") });
|
||||
}
|
||||
return `<h${depth} id="${id}">${html}</h${depth}>`;
|
||||
},
|
||||
code({ text, lang }: Tokens.Code) {
|
||||
const [language = "", ...rest] = (lang ?? "").split(/\s+/);
|
||||
const example = rest.find((part) => part.startsWith("example="))?.slice("example=".length);
|
||||
let code = text;
|
||||
let caption = language;
|
||||
if (example) {
|
||||
const body = examples[`../../../examples/docs/${example}.rs`];
|
||||
if (body === undefined) throw new Error(`docs: ${file}.md names a missing example ${example}`);
|
||||
code = body.trimEnd();
|
||||
caption = `examples/docs/${example}.rs · cargo run --example docs_${example}`;
|
||||
}
|
||||
return `<figure class="code"><figcaption>${escape(caption)}</figcaption><button class="copy" type="button">Copy</button><pre><code>${escape(code)}</code></pre></figure>`;
|
||||
},
|
||||
},
|
||||
});
|
||||
const html = marked.parse(source, { async: false });
|
||||
if (!title) throw new Error(`docs: ${file}.md has no # title`);
|
||||
return { slug: file === "introduction" ? "" : file, title, html, toc };
|
||||
}
|
||||
|
||||
export const guides: Guide[] = ORDER.map(read);
|
||||
@@ -0,0 +1,14 @@
|
||||
# Introduction
|
||||
|
||||
Ely is a component library for [GPUI](https://www.gpui.rs), the Rust UI framework behind Zed. Every component draws in light and dark, and every one runs live on the [components page](/components/).
|
||||
|
||||
## A first window
|
||||
|
||||
The example opens a window with one counter and one Button. `cargo run --example docs_hello` runs it from a clone of the repository.
|
||||
|
||||
```rust example=hello
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT or Apache-2.0, at your option.
|
||||
Reference in new issue
Block a user