Skip to content

Commit

Permalink
feat: Monaco (#1)
Browse files Browse the repository at this point in the history
* feat: Replace existing editor with monaco
* feat: Plugin responses are now pretty printed.
* feat: Better dark mode support.
* fix: Addressed headers not respecting safe area insets.
* fix: Modal was actually being retained. It is now properly disposed.
  • Loading branch information
Steven0351 authored Dec 8, 2023
1 parent f9259e3 commit 97ef7a5
Show file tree
Hide file tree
Showing 8 changed files with 337 additions and 255 deletions.
64 changes: 55 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 10 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,37 @@
"version": "0.0.1",
"type": "module",
"scripts": {
"dev": "vite",
"dev": "vite --host",
"build": "tsc && vite build",
"preview": "vite preview",
"test.e2e": "cypress run",
"test.unit": "vitest",
"lint": "eslint"
},
"dependencies": {
"@capacitor/app": "5.0.6",
"@capacitor/core": "5.2.2",
"@capacitor/haptics": "5.0.6",
"@capacitor/keyboard": "5.0.6",
"@capacitor/status-bar": "5.0.6",
"@capacitor/app": "^5.0.6",
"@capacitor/core": "^5.2.2",
"@capacitor/haptics": "^5.0.6",
"@capacitor/keyboard": "^5.0.6",
"@capacitor/status-bar": "^5.0.6",
"@ionic/core": "^7.3.0",
"@ionic/portals": "^0.8.1",
"@ionic/react": "^7.0.0",
"@ionic/react-router": "^7.0.0",
"@monaco-editor/react": "^4.6.0",
"@types/react-router": "^5.1.20",
"@types/react-router-dom": "^5.3.3",
"ionicons": "^7.0.0",
"monaco-editor": "^0.44.0",
"react": "^18.2.0",
"react-ace": "^10.1.0",
"react-dom": "^18.2.0",
"react-router": "^5.3.4",
"react-router-dom": "^5.3.4"
},
"devDependencies": {
"@capacitor/cli": "5.2.2",
"@capacitor/cli": "^5.2.2",
"@capacitor/ios": "^5.5.0",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.4.3",
Expand Down
168 changes: 81 additions & 87 deletions src/components/CallMethodModal.tsx
Original file line number Diff line number Diff line change
@@ -1,54 +1,49 @@
import {
IonModal,
IonContent,
IonListHeader,
IonButton,
IonHeader,
IonToolbar,
IonTitle,
IonButtons,
IonIcon,
IonItem,
IonTextarea,
IonLabel,
IonList,
} from "@ionic/react";
import { useState } from "react";
import { useEffect, useRef, useState } from "react";
import {
chevronBack,
alertCircleOutline,
checkmarkCircleOutline,
} from "ionicons/icons";
import AceEditor from "react-ace";
import "ace-builds/src-noconflict/mode-json";
import "ace-builds/src-noconflict/theme-github";
import Editor, { useMonaco } from "@monaco-editor/react";

interface CallMethodModalProps {
showModal: boolean;
pluginName: string;
methodName: string;
onCloseModal: () => void;
}

const darkModeMatch = window.matchMedia("(prefers-color-scheme: dark)");

const CallMethodModal: React.FC<CallMethodModalProps> = ({
showModal,
pluginName,
methodName,
onCloseModal,
}) => {
const [code, setCode] = useState<string>("");
const codeRef = useRef("{}");
const monaco = useMonaco();
const [result, setResult] = useState<string>("");
const [error, setError] = useState<string>("");

useEffect(() => {
monaco?.editor.setTheme(darkModeMatch.matches ? "vs-dark" : "vs")
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", (_e) => {
monaco?.editor.setTheme(darkModeMatch.matches ? "vs-dark" : "vs")
});
}, []);

const handleCallMethod = async () => {
setResult("");
setError("");
try {
// @ts-ignore
const res = await window.Capacitor.Plugins[pluginName][methodName](
JSON.parse(code || '""')
);
setResult(JSON.stringify(res));
const res = await window.Capacitor.Plugins[pluginName][methodName](JSON.parse(codeRef.current));
setResult(JSON.stringify(res, null, 2));
} catch (error) {
if (error instanceof Error) {
setError(error.message);
Expand All @@ -58,82 +53,81 @@ const CallMethodModal: React.FC<CallMethodModalProps> = ({
}
};

const handleCloseModal = () => {
setCode("");
setResult("");
setError("");
onCloseModal();
};

return (
<IonModal isOpen={showModal} onDidDismiss={handleCloseModal}>
<IonHeader>
<IonToolbar>
<IonButtons>
<IonButton onClick={handleCloseModal}>
<IonIcon icon={chevronBack} />
Back
</IonButton>
</IonButtons>
<IonTitle>{methodName}</IonTitle>
<IonButtons slot="end">
<IonButton onClick={handleCallMethod}>Execute</IonButton>
</IonButtons>
</IonToolbar>
</IonHeader>
<IonContent className="ion-padding">
<IonListHeader>Argument:</IonListHeader>
<IonList>
<IonItem>
<AceEditor
height="200px"
value={code}
placeholder="Enter valid JSON here..."
mode="json"
theme="github"
fontSize="13px"
highlightActiveLine={true}
onChange={(e) => setCode(e)}
setOptions={{
showLineNumbers: true,
tabSize: 2,
useWorker: false,
}}
style={{ marginTop: 10 }}
/>
<IonContent className="ion-padding">
<IonHeader>Argument:</IonHeader>
<Editor
onMount={(_editor, monaco) => {
monaco.editor.setTheme(darkModeMatch.matches ? "vs-dark" : "vs")
}}
height="200px"
defaultLanguage="json"
defaultValue={codeRef.current}
onChange={(e) => codeRef.current = e ?? ""}
options={{
accessibilitySupport: "off",
theme: darkModeMatch.matches ? "vs-dark" : "vs",
lineDecorationsWidth: 0,
glyphMargin: false,
inlineSuggest: {
enabled: false
},
quickSuggestions: false,
suggestOnTriggerCharacters: false,
parameterHints: {
enabled: false
},
inlayHints: {
enabled: "off"
},
lineNumbersMinChars: 2,
folding: false,
lineNumbers: "on",
scrollbar: {
vertical: "hidden",
horizontal: "hidden",
},
minimap: {
enabled: false,
},
}}
/>
<IonButton
expand="block"
onClick={handleCallMethod}
size="small"
style={{ padding: 10 }}
>
Execute {methodName}
</IonButton>
<IonList lines="inset">
{error && (
<IonItem color="light">
<IonIcon icon={alertCircleOutline} slot="start" color="danger" />
<IonLabel color="danger" class="ion-text-wrap">
{error}
</IonLabel>
</IonItem>
<IonButton
expand="block"
onClick={handleCallMethod}
size="small"
style={{ padding: 10 }}
>
Execute {methodName}
</IonButton>
</IonList>
<IonListHeader>Result:</IonListHeader>
<IonList lines="inset">
{error && (
<IonItem color="light">
<IonIcon icon={alertCircleOutline} slot="start" color="danger" />
<IonLabel color="danger" class="ion-text-wrap">
{error}
</IonLabel>
</IonItem>
)}
{result && (
)}
{result && (
<>
<IonItem color="light">
<IonIcon
icon={checkmarkCircleOutline}
color="success"
slot="start"
/>
<IonLabel class="ion-text-wrap">{result}</IonLabel>
<IonLabel>Success</IonLabel>
</IonItem>
<IonItem color="light">
<IonLabel style={{ whiteSpace: "pre-wrap" }}>
<code>{result}</code>
</IonLabel>
</IonItem>
)}
</IonList>
</IonContent>
</IonModal>
</>
)}
</IonList>
</IonContent>
);
};

Expand Down
Loading

0 comments on commit 97ef7a5

Please sign in to comment.