forked from bots-garden/ori
| ✨ Workspace panel, selectors, previews, desktop app, sandbox template, resizable file tree, light/dark theme | 1 | /** |
| 2 | * AsciiDocView renders an AsciiDoc document to HTML with Asciidoctor, | |
| 3 | * lazy-loading the (heavy) converter on first use. | |
| 4 | * | |
| 5 | * The converted HTML comes from files in the user's own workspace, rendered | |
| 6 | * for the user who owns them — the same trust model as opening the file in | |
| 7 | * any editor's preview. | |
| 8 | * | |
| 9 | * @example | |
| 10 | * <AsciiDocView content="= Title" /> | |
| 11 | */ | |
| 12 | ||
| 13 | import { useEffect, useState } from "react"; | |
| 14 | ||
| 15 | export function AsciiDocView({ content }: { content: string }) { | |
| 16 | const [html, setHtml] = useState<string | null>(null); | |
| 17 | const [error, setError] = useState<string | null>(null); | |
| 18 | ||
| 19 | useEffect(() => { | |
| 20 | let cancelled = false; | |
| 21 | // @asciidoctor/core v4 exposes an async convert() as a named export | |
| 22 | // (the v3 synchronous asciidoctor() factory is gone). | |
| 23 | import("@asciidoctor/core") | |
| 24 | .then(({ convert }) => | |
| 25 | convert(content, { | |
| 26 | safe: "safe", | |
| 27 | attributes: { showtitle: true, icons: "font" }, | |
| 28 | }), | |
| 29 | ) | |
| 30 | .then((converted) => { | |
| 31 | if (!cancelled) { | |
| 32 | setHtml(String(converted)); | |
| 33 | } | |
| 34 | }) | |
| 35 | .catch((cause: Error) => { | |
| 36 | if (!cancelled) { | |
| 37 | setError(`AsciiDoc rendering failed: ${cause.message}`); | |
| 38 | } | |
| 39 | }); | |
| 40 | return () => { | |
| 41 | cancelled = true; | |
| 42 | }; | |
| 43 | }, [content]); | |
| 44 | ||
| 45 | if (error) { | |
| 46 | return <p className="pane-error">{error}</p>; | |
| 47 | } | |
| 48 | if (html === null) { | |
| 49 | return <p className="pane-empty">rendering…</p>; | |
| 50 | } | |
| 51 | return ( | |
| 52 | <div | |
| 53 | className="markdown asciidoc" | |
| 54 | // biome-ignore lint/security/noDangerouslySetInnerHtml: Asciidoctor's output over the user's own workspace files, converted in safe mode — the accepted pattern for a local document preview. | |
| 55 | dangerouslySetInnerHTML={{ __html: html }} | |
| 56 | /> | |
| 57 | ); | |
| 58 | } |