Skip to content

Commit d558c00

Browse files
committed
chore: make the original+overlay tab pretty
1 parent 74abdb1 commit d558c00

File tree

3 files changed

+898
-848
lines changed

3 files changed

+898
-848
lines changed

web/src/Playground.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import posthog from "posthog-js";
2929
import { useDebounceCallback, useMediaQuery } from "usehooks-ts";
3030

3131
const originalOpenAPI = atom(petstore);
32-
const changedOpenAPI = atom(petstore);
32+
const changedOpenAPI = atom<string>("");
3333
const overlay = atom(blankOverlay);
3434
const Link = ({ children, href }: { children: ReactNode; href: string }) => (
3535
<a
@@ -129,6 +129,9 @@ function Playground() {
129129
} catch (error: any) {
130130
console.error("invalid share url:", error.message);
131131
}
132+
} else {
133+
const changed = await ApplyOverlay(original, result, false);
134+
setChanged(changed);
132135
}
133136
setReady(true);
134137
})();
@@ -364,6 +367,7 @@ function Playground() {
364367
<div style={{ height: "calc(100vh - 50px)" }}>
365368
<Editor
366369
readonly={false}
370+
original={original}
367371
value={changed}
368372
onChange={onChangeBDebounced}
369373
loading={changedLoading}

web/src/components/Editor.tsx

Lines changed: 84 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,21 @@ import React, {
55
useRef,
66
useState,
77
} from "react";
8-
import MonacoEditor, { Monaco } from "@monaco-editor/react";
9-
import { editor } from "monaco-editor";
8+
import MonacoEditor, { Monaco, DiffEditor } from "@monaco-editor/react";
9+
import { editor, Uri } from "monaco-editor";
1010
import { Progress } from "../../@/components/ui/progress";
1111
import { Icon } from "@speakeasy-api/moonshine";
1212
import { Button } from "@/components/ui/button";
13+
import IModelContentChangedEvent = editor.IModelContentChangedEvent;
14+
import ITextModel = editor.ITextModel;
15+
import ICodeEditor = editor.ICodeEditor;
1316

1417
export interface EditorComponentProps {
1518
readonly: boolean;
1619
value: string;
20+
original?: string;
1721
loading?: boolean;
18-
title?: string;
22+
title: string;
1923
index: number;
2024
maxOnClick?: (index: number) => void;
2125
onChange: (
@@ -27,51 +31,89 @@ export interface EditorComponentProps {
2731
const minLoadingTime = 150;
2832

2933
export function Editor(props: EditorComponentProps) {
30-
const editorRef = useRef<any>(null);
34+
const editorRef = useRef<ICodeEditor | null>(null);
3135
const monacoRef = useRef<Monaco | null>(null);
36+
const modelRef = useRef<ITextModel | null>(null);
3237
const [lastLoadingTime, setLastLoadingTime] = useState(minLoadingTime);
3338
const [progress, setProgress] = useState(100);
3439

35-
const handleEditorDidMount = useCallback((editor: any, monaco: Monaco) => {
36-
editorRef.current = editor;
37-
monacoRef.current = monaco;
40+
const encodedTitle = useMemo(() => {
41+
return btoa(props.title);
42+
}, [props.title]);
3843

39-
const options = {
40-
base: "vs-dark",
41-
renderSideBySide: false,
42-
inherit: true,
43-
rules: [
44-
{
45-
foreground: "F3F0E3",
46-
token: "string",
47-
},
48-
{
49-
foreground: "679FE1",
50-
token: "type",
51-
},
52-
],
53-
colors: {
54-
"editor.foreground": "#F3F0E3",
55-
"editor.background": "#212015",
56-
"editorCursor.foreground": "#679FE1",
57-
"editor.lineHighlightBackground": "#1D2A3A",
58-
"editorLineNumber.foreground": "#6368747F",
59-
"editorLineNumber.activeForeground": "#FBE331",
60-
"editor.inactiveSelectionBackground": "#FF3C742D",
61-
"diffEditor.removedTextBackground": "#FF3C741A",
62-
"diffEditor.insertedTextBackground": "#1D2A3A",
63-
},
44+
const EditorComponent =
45+
props.original === undefined ? MonacoEditor : DiffEditor;
46+
47+
const onChange = useCallback(
48+
(value: string, event: IModelContentChangedEvent) => {
49+
props.onChange(value, event);
50+
},
51+
[props.onChange],
52+
);
53+
54+
const handleEditorWillMount = useCallback((monaco: Monaco) => {
55+
monacoRef.current = monaco;
56+
const matchesURI = (uri: Uri | undefined) => {
57+
return uri?.path.includes(encodedTitle);
6458
};
65-
// @ts-ignore
66-
monaco.editor.defineTheme("speakeasy", options);
67-
monaco.editor.setTheme("speakeasy");
59+
monaco.editor.onDidCreateModel((model) => {
60+
if (!matchesURI(model.uri)) {
61+
return;
62+
}
63+
if (props.original && !model.uri.path.includes("modified")) {
64+
return;
65+
}
66+
67+
modelRef.current = model;
68+
modelRef.current.onDidChangeContent((event) => {
69+
if (editorRef.current?.hasTextFocus()) {
70+
onChange(model.getValue(), event);
71+
}
72+
});
73+
});
6874
}, []);
6975

76+
const handleEditorDidMount = useCallback(
77+
(editor: ICodeEditor, monaco: Monaco) => {
78+
editorRef.current = editor;
79+
80+
const options = {
81+
base: "vs-dark",
82+
inherit: true,
83+
rules: [
84+
{
85+
foreground: "F3F0E3",
86+
token: "string",
87+
},
88+
{
89+
foreground: "679FE1",
90+
token: "type",
91+
},
92+
],
93+
colors: {
94+
"editor.foreground": "#F3F0E3",
95+
"editor.background": "#212015",
96+
"editorCursor.foreground": "#679FE1",
97+
"editor.lineHighlightBackground": "#1D2A3A",
98+
"editorLineNumber.foreground": "#6368747F",
99+
"editorLineNumber.activeForeground": "#FBE331",
100+
"editor.inactiveSelectionBackground": "#FF3C742D",
101+
"diffEditor.removedTextBackground": "#FF3C741A",
102+
"diffEditor.insertedTextBackground": "#1D2A3A",
103+
},
104+
} satisfies editor.IStandaloneThemeData;
105+
monaco.editor.defineTheme("speakeasy", options);
106+
monaco.editor.setTheme("speakeasy");
107+
},
108+
[onChange],
109+
);
110+
70111
const options: any = useMemo(
71112
() => ({
72113
readOnly: props.readonly,
73114
minimap: { enabled: false },
74115
automaticLayout: true,
116+
renderSideBySide: false,
75117
}),
76118
[props.readonly],
77119
);
@@ -152,10 +194,15 @@ export function Editor(props: EditorComponentProps) {
152194
</h1>
153195
</div>
154196
)}
155-
<MonacoEditor
197+
<EditorComponent
156198
onMount={handleEditorDidMount}
199+
beforeMount={handleEditorWillMount}
200+
original={props.original}
201+
modified={props.value}
157202
value={props.value}
158-
onChange={props.onChange}
203+
path={encodedTitle}
204+
originalModelPath={encodedTitle + "/original"}
205+
modifiedModelPath={encodedTitle + "/modified"}
159206
theme={"vscode-dark"}
160207
language="yaml"
161208
options={options}

0 commit comments

Comments
 (0)