feat: revamp demo

This commit is contained in:
Justineo
2025-09-24 01:27:35 +08:00
committed by GU Yiling
parent 1da2bf7811
commit def0ad5bf5
47 changed files with 4180 additions and 1740 deletions

248
demo/services/monaco.ts Normal file
View File

@ -0,0 +1,248 @@
import * as monaco from "monaco-editor/esm/vs/editor/editor.api";
import "monaco-editor/esm/vs/basic-languages/javascript/javascript.contribution";
import "monaco-editor/esm/vs/basic-languages/typescript/typescript.contribution";
import "monaco-editor/esm/vs/language/json/monaco.contribution";
import "monaco-editor/esm/vs/language/typescript/monaco.contribution";
import editorWorker from "monaco-editor/esm/vs/editor/editor.worker?worker";
import tsWorker from "monaco-editor/esm/vs/language/typescript/ts.worker?worker";
import jsonWorker from "monaco-editor/esm/vs/language/json/json.worker?worker";
const globalWithMonaco = globalThis as typeof globalThis & {
MonacoEnvironment?: {
getWorker: (moduleId: string, label: string) => Worker;
};
};
if (!globalWithMonaco.MonacoEnvironment) {
globalWithMonaco.MonacoEnvironment = {
getWorker(_: string, label: string) {
if (label === "json") {
return new jsonWorker();
}
if (label === "typescript" || label === "javascript") {
return new tsWorker();
}
return new editorWorker();
},
};
}
const diagnosticsOptions: monaco.languages.typescript.DiagnosticsOptions = {
noSemanticValidation: true,
noSyntaxValidation: true,
noSuggestionDiagnostics: true,
};
monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions(
diagnosticsOptions,
);
monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions(
diagnosticsOptions,
);
monaco.languages.typescript.javascriptDefaults.setEagerModelSync(true);
monaco.languages.typescript.typescriptDefaults.setEagerModelSync(true);
export type MonacoSeverity = "error" | "warning" | "info" | "hint";
export interface MonacoMarkerLike {
startLineNumber: number;
startColumn: number;
endLineNumber: number;
endColumn: number;
message: string;
code?: string;
source?: string;
severity?: MonacoSeverity;
}
const SEVERITY_MAP: Record<MonacoSeverity, monaco.MarkerSeverity> = {
error: monaco.MarkerSeverity.Error,
warning: monaco.MarkerSeverity.Warning,
info: monaco.MarkerSeverity.Info,
hint: monaco.MarkerSeverity.Hint,
};
export interface OptionEditor {
editor: monaco.editor.IStandaloneCodeEditor;
getValue(): string;
setValue(value: string): void;
setMarkers(markers: readonly MonacoMarkerLike[]): void;
setTheme(theme: string): void;
dispose(): void;
}
export interface CodeViewer {
editor: monaco.editor.IStandaloneCodeEditor;
setValue(value: string): void;
setTheme(theme: string): void;
setLanguage(language: string): void;
dispose(): void;
}
export interface CreateOptionEditorOptions {
initialCode: string;
language?: string;
onChange?: (code: string) => void;
theme?: string;
}
export interface CreateCodeViewerOptions {
initialCode: string;
language?: string;
theme?: string;
}
const MARKER_OWNER = "ve-codegen-option";
export function createOptionEditor(
container: HTMLElement,
{
initialCode,
language = "typescript",
onChange,
theme = "vs",
}: CreateOptionEditorOptions,
): OptionEditor {
monaco.editor.setTheme(theme);
const editor = monaco.editor.create(container, {
value: initialCode,
language,
automaticLayout: true,
scrollBeyondLastLine: false,
minimap: { enabled: false },
fontSize: 13,
lineHeight: 20,
tabSize: 2,
insertSpaces: true,
wordWrap: "on",
});
const disposables: monaco.IDisposable[] = [];
if (onChange) {
disposables.push(
editor.onDidChangeModelContent(() => {
const model = editor.getModel();
if (!model) {
return;
}
onChange(model.getValue());
}),
);
}
function getValue() {
return editor.getValue();
}
function setValue(value: string) {
const model = editor.getModel();
if (!model) {
return;
}
if (model.getValue() !== value) {
model.setValue(value);
}
}
function setMarkers(markers: readonly MonacoMarkerLike[]) {
const model = editor.getModel();
if (!model) {
return;
}
const mapped = markers.map((marker) => ({
...marker,
severity: marker.severity
? SEVERITY_MAP[marker.severity]
: monaco.MarkerSeverity.Error,
}));
monaco.editor.setModelMarkers(model, MARKER_OWNER, mapped);
}
function dispose() {
disposables.forEach((item) => item.dispose());
disposables.length = 0;
const model = editor.getModel();
if (model) {
monaco.editor.setModelMarkers(model, MARKER_OWNER, []);
}
editor.dispose();
}
function setTheme(nextTheme: string) {
monaco.editor.setTheme(nextTheme);
}
return {
editor,
getValue,
setValue,
setMarkers,
setTheme,
dispose,
};
}
export function createCodeViewer(
container: HTMLElement,
{
initialCode,
language = "javascript",
theme = "vs",
}: CreateCodeViewerOptions,
): CodeViewer {
monaco.editor.setTheme(theme);
const editor = monaco.editor.create(container, {
value: initialCode,
language,
automaticLayout: true,
scrollBeyondLastLine: false,
minimap: { enabled: false },
fontSize: 13,
lineHeight: 20,
tabSize: 2,
insertSpaces: true,
wordWrap: "on",
readOnly: true,
renderLineHighlight: "none",
});
function setValue(value: string) {
const model = editor.getModel();
if (!model) {
return;
}
if (model.getValue() !== value) {
model.setValue(value);
}
}
function setTheme(nextTheme: string) {
monaco.editor.setTheme(nextTheme);
}
function setLanguage(nextLanguage: string) {
const model = editor.getModel();
if (!model) {
return;
}
monaco.editor.setModelLanguage(model, nextLanguage);
}
function dispose() {
editor.dispose();
}
return {
editor,
setValue,
setTheme,
setLanguage,
dispose,
};
}
export { monaco };
export type MonacoNamespace = typeof monaco;