Files
CodeNomad/packages/ui/src/components/file-viewer/monaco-file-viewer.tsx
Shantur Rathore b59e85abda feat(ui): add Monaco changes/files right drawer viewers
Use OpenCode v2 file APIs for browsing and Monaco DiffEditor for session snapshot diffs, with local baseline language metadata and optional CDN language loading.
2026-02-09 21:00:40 +00:00

90 lines
2.2 KiB
TypeScript

import { createEffect, createSignal, onCleanup, onMount } from "solid-js"
import { loadMonaco } from "../../lib/monaco/setup"
import { getOrCreateTextModel } from "../../lib/monaco/model-cache"
import { inferMonacoLanguageId } from "../../lib/monaco/language"
import { ensureMonacoLanguageLoaded } from "../../lib/monaco/setup"
import { useTheme } from "../../lib/theme"
interface MonacoFileViewerProps {
scopeKey: string
path: string
content: string
}
export function MonacoFileViewer(props: MonacoFileViewerProps) {
const { isDark } = useTheme()
let host: HTMLDivElement | undefined
let editor: any = null
let monaco: any = null
const [ready, setReady] = createSignal(false)
const disposeEditor = () => {
try {
editor?.setModel(null)
} catch {
// ignore
}
try {
editor?.dispose()
} catch {
// ignore
}
editor = null
}
onMount(() => {
let cancelled = false
void (async () => {
monaco = await loadMonaco()
if (cancelled) return
if (!host || !monaco) return
monaco.editor.setTheme(isDark() ? "vs-dark" : "vs")
editor = monaco.editor.create(host, {
value: "",
language: "plaintext",
readOnly: true,
automaticLayout: true,
lineNumbers: "on",
minimap: { enabled: false },
scrollBeyondLastLine: false,
wordWrap: "off",
renderWhitespace: "selection",
fontSize: 13,
})
setReady(true)
})()
onCleanup(() => {
cancelled = true
setReady(false)
disposeEditor()
})
})
createEffect(() => {
if (!ready() || !monaco || !editor) return
monaco.editor.setTheme(isDark() ? "vs-dark" : "vs")
})
createEffect(() => {
if (!ready() || !monaco || !editor) return
const languageId = inferMonacoLanguageId(monaco, props.path)
const cacheKey = `${props.scopeKey}:file:${props.path}`
const model = getOrCreateTextModel({ monaco, cacheKey, value: props.content, languageId })
editor.setModel(model)
void ensureMonacoLanguageLoaded(languageId).then(() => {
try {
monaco.editor.setModelLanguage(model, languageId)
} catch {
// ignore
}
})
})
return <div class="monaco-viewer" ref={host} />
}