/** * Monaco, self-hosted and themed from the design tokens. * * Only the base editor, the Python grammar and JSON (for settings holding JSON) * are pulled in; the other seventy languages would triple the chunk for * nothing. This module is imported by NodeEditor alone, which the panel loads * lazily. */ import { loader } from "@monaco-editor/react" import * as monaco from "monaco-editor/editor/editor.api" // Only Python registers itself; `basic-languages` would pull in all seventy. import "monaco-editor/languages/definitions/python/register" import "monaco-editor/languages/features/json/register" import editorWorker from "monaco-editor/editor/editor.worker?worker" import jsonWorker from "monaco-editor/languages/features/json/json.worker?worker" let configured = false function defineThemes() { const themes = [ { id: "fluksio-light", base: "vs" as const }, { id: "fluksio-dark", base: "vs-dark" as const }, ] for (const theme of themes) { const dark = theme.id.endsWith("dark") const background = dark ? "#1a1a1a" : "#ffffff" const foreground = dark ? "#f5f5f5" : "#333232" const muted = dark ? "#a3a3a3" : "#6b6b6b" const accent = dark ? "#262626" : "#f5f5f5" const primary = dark ? "#7ba3b8" : "#4a7189" const success = dark ? "#87b596" : "#5e8b6d" monaco.editor.defineTheme(theme.id, { base: theme.base, inherit: true, rules: [ { token: "keyword", foreground: primary.slice(1) }, { token: "string", foreground: success.slice(1) }, { token: "comment", foreground: muted.slice(1), fontStyle: "italic" }, { token: "number", foreground: foreground.slice(1) }, // JSON names its tokens more specifically, so the base theme's // colours would win over the generic ones above. { token: "string.key.json", foreground: foreground.slice(1) }, { token: "string.value.json", foreground: success.slice(1) }, { token: "keyword.json", foreground: primary.slice(1) }, ], colors: { "editor.background": background, "editor.foreground": foreground, "editorLineNumber.foreground": muted, "editorLineNumber.activeForeground": foreground, "editor.lineHighlightBackground": accent, "editorCursor.foreground": primary, "editor.selectionBackground": `${primary}33`, "editorIndentGuide.background1": accent, "editorWidget.background": background, "editorGutter.background": background, }, }) } } export function setupMonaco(): typeof monaco { if (configured) return monaco configured = true // Self-hosted: no CDN fetch, so the editor works on a LAN install. self.MonacoEnvironment = { getWorker: (_, label) => label === "json" ? new jsonWorker() : new editorWorker(), } loader.config({ monaco }) defineThemes() return monaco } export const monacoFontFamily = (): string => getComputedStyle(document.documentElement) .getPropertyValue("--font-mono") .trim() || "ui-monospace, monospace"