mirror of
https://github.com/anomalyco/opencode.git
synced 2026-11-01 16:11:19 +00:00
103 lines
3.7 KiB
TypeScript
103 lines
3.7 KiB
TypeScript
import { createSignal, Show } from "solid-js"
|
|
import { render } from "solid-js/web"
|
|
import { DialogProvider } from "@opencode/ui/context/dialog"
|
|
import { I18nProvider, useI18n } from "@opencode/ui/context/i18n"
|
|
import { Markdown } from "../src/components/markdown"
|
|
import { preloadMarkdown } from "../src/components/markdown-cache"
|
|
import { MarkdownProvider, type MarkdownLocalFileExists } from "../src/context/markdown"
|
|
import { OpenCode } from "@opencode/client/promise"
|
|
import { readLocalImage } from "../../app/src/runtime/server/image"
|
|
|
|
export {
|
|
getCachedMarkdown,
|
|
renderCachedMarkdown,
|
|
sanitizeMarkdown,
|
|
touchCachedMarkdown,
|
|
} from "../src/components/markdown-cache"
|
|
|
|
export { renderMermaidSvg } from "../src/components/markdown-mermaid"
|
|
|
|
export { MarkdownWorkerDisposedError } from "../src/components/markdown-worker"
|
|
|
|
export { preloadMarkdown }
|
|
|
|
// Inline code naming one of these is a file link; any other path stays plain code.
|
|
const existingFiles = new Set(["src/file.ts", "new/file.ts"])
|
|
|
|
export async function mountMarkdown(options: {
|
|
text: string
|
|
streaming?: boolean
|
|
cached?: boolean
|
|
images?: boolean
|
|
synchronousFiles?: boolean
|
|
localFileExists?: MarkdownLocalFileExists
|
|
}) {
|
|
if (options.cached) await preloadMarkdown(options.text, "markdown-test")
|
|
const host = document.createElement("div")
|
|
host.dataset.testid = "markdown-fixture"
|
|
document.body.appendChild(host)
|
|
render(() => {
|
|
const api = OpenCode.make({
|
|
baseUrl: location.origin,
|
|
headers: { Authorization: `Basic ${btoa("opencode:fixture")}` },
|
|
})
|
|
|
|
const [text, setText] = createSignal(options.text)
|
|
const [streaming, setStreaming] = createSignal(options.streaming ?? false)
|
|
const [visible, setVisible] = createSignal(true)
|
|
const [german, setGerman] = createSignal(false)
|
|
const english = useI18n()
|
|
|
|
return (
|
|
<DialogProvider>
|
|
<textarea aria-label="Markdown text" value={text()} onInput={(event) => setText(event.currentTarget.value)} />
|
|
<input
|
|
aria-label="Streaming"
|
|
type="checkbox"
|
|
checked={streaming()}
|
|
onChange={(event) => setStreaming(event.currentTarget.checked)}
|
|
/>
|
|
<input
|
|
aria-label="German"
|
|
type="checkbox"
|
|
checked={german()}
|
|
onChange={(event) => setGerman(event.currentTarget.checked)}
|
|
/>
|
|
<button onClick={() => setVisible((value) => !value)}>Toggle Markdown</button>
|
|
<I18nProvider
|
|
value={{
|
|
locale: () => (german() ? "de" : "en"),
|
|
t: (key, params) => (german() && key === "ui.message.copy" ? "Kopieren" : english.t(key, params)),
|
|
plural: english.plural,
|
|
pluralForm: english.pluralForm,
|
|
}}
|
|
>
|
|
<MarkdownProvider
|
|
readImage={(path, signal) =>
|
|
options.images ? readLocalImage(api, "C:/project", path, signal) : Promise.resolve(undefined)
|
|
}
|
|
localFileExists={(path) =>
|
|
options.localFileExists?.(path) ??
|
|
(options.synchronousFiles ? existingFiles.has(path) : Promise.resolve(existingFiles.has(path)))
|
|
}
|
|
>
|
|
<Show when={visible()}>
|
|
<Markdown
|
|
text={text()}
|
|
streaming={streaming()}
|
|
cacheKey={options.cached ? "markdown-test" : undefined}
|
|
deferUntilReady
|
|
/>
|
|
</Show>
|
|
</MarkdownProvider>
|
|
</I18nProvider>
|
|
</DialogProvider>
|
|
)
|
|
}, host)
|
|
|
|
// Capture before Promise callbacks run: eventual assertions cannot catch a flash on insertion.
|
|
return Array.from(host.querySelectorAll<HTMLElement>(":not(pre) > code"), (node) => ({
|
|
text: node.textContent,
|
|
kind: node.dataset.inlineCodeKind ?? null,
|
|
}))
|
|
}
|