Skip to content

Commit

Permalink
refactor: extract Editor component
Browse files Browse the repository at this point in the history
  • Loading branch information
octokatherine authored Oct 29, 2021
1 parent 60a826b commit 05117cd
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 92 deletions.
101 changes: 9 additions & 92 deletions example-nextjs/components/CodeRunnerUI.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import * as React from 'react'
import Editor, { Monaco } from '@monaco-editor/react'
import Script from 'next/script'
import GithubButton from './GithubButton'
import Navbar from './Navbar'
import { addKeyBinding, CustomKeyBinding } from '../utils'
import Editor from './Editor'

interface Props {
defaultLanguage?: string
Expand All @@ -25,35 +24,6 @@ export default function CodeRunnerUI(props: Props) {
children,
onRunCode,
} = props
const inputCodeRef = React.useRef(initialCode)
const [output, setOutput] = React.useState('')
const editorRef = React.useRef(null)
const [monaco, setMonaco] = React.useState<Monaco>(null)

async function runCode(code: string) {
const output = await onRunCode(code)
if (output) {
setOutput(output)
}
}

function handleEditorDidMount(editor: any, monaco: Monaco) {
editorRef.current = editor
setMonaco(monaco)
}

React.useEffect(() => {
if (!monaco || isLoading) {
return
}
const runCodeBinding: CustomKeyBinding = {
label: 'run',
keybinding: monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter,
callback: () => runCode(inputCodeRef.current),
editor: editorRef.current,
}
return addKeyBinding(runCodeBinding)
}, [monaco, isLoading])

return (
<>
Expand All @@ -80,68 +50,15 @@ export default function CodeRunnerUI(props: Props) {
<GithubButton />
</div>
</main>

<div>
<label className="block pb-4 text-sm font-medium text-gray-700 dark:text-gray-450">
{languageLabel}
</label>

<div className="mt-1 ">
<div className="relative group">
<div className="absolute -inset-0.5 dark:bg-gradient-to-r from-indigo-300 to-purple-400 rounded-lg blur opacity-25 group-hover:opacity-100 transition duration-1000 group-hover:duration-200 animate-tilt" />
<Editor
height="20rem"
defaultLanguage={defaultLanguage}
defaultValue={inputCodeRef.current}
onChange={(value) => {
inputCodeRef.current = value
}}
className="block w-1/2 text-white bg-gray-900 border-gray-300 rounded-lg shadow-sm p-0.5 border dark:border-purple-300 focus:ring-gray-500 focus:border-gray-500 sm:text-sm"
theme="vs-dark"
options={{ fontSize: 12 }}
onMount={handleEditorDidMount}
/>
</div>
</div>
</div>

<div className="pt-8 ">
<div className="grid items-start justify-left">
<div className="relative group">
<button
className="relative flex items-center py-4 leading-none bg-black divide-x divide-gray-600 rounded-lg px-7 border-gray-300 disabled:bg-gray-700 disabled:cursor-not-allowed"
onClick={() => runCode(inputCodeRef.current)}
disabled={isLoading}
>
<span className="text-gray-100 transition duration-200 group-hover:text-gray-100">
{!isLoading ? 'Run Code →' : `Loading ${languageLabel}...`}
</span>
</button>
</div>
</div>
</div>

{children}

{!hideOutputEditor && (
<div>
<label className="block pt-8 text-sm font-medium text-gray-700 dark:text-gray-450">
Output
</label>

<div className="mt-1 dark:text-gray-450">
<Editor
value={output?.toString()}
height="20rem"
defaultLanguage="python"
className="block w-1/2 text-white bg-gray-900 border-gray-300 rounded-lg shadow-sm p-0.5 border dark:border-purple-300 focus:ring-gray-500 focus:border-gray-500 sm:text-sm"
theme="vs-dark"
options={{ readOnly: true }}
/>
</div>
</div>
)}
</div>
<Editor
initialCode={initialCode}
languageLabel={languageLabel}
hideOutputEditor={hideOutputEditor}
isLoading={isLoading}
defaultLanguage={defaultLanguage}
onRunCode={onRunCode}
/>
</div>
</>
)
Expand Down
123 changes: 123 additions & 0 deletions example-nextjs/components/Editor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import * as React from 'react'
import MonacoEditor, { Monaco } from '@monaco-editor/react'
import { addKeyBinding, CustomKeyBinding } from '../utils'

interface Props {
initialCode: string
languageLabel: string
hideOutputEditor?: boolean
isLoading?: boolean
defaultLanguage?: string
onRunCode(inputCode: string): Promise<string | void>
children?: React.ReactNode
}

export default function Editor(props: Props) {
const {
initialCode,
languageLabel,
hideOutputEditor,
isLoading = false,
defaultLanguage,
onRunCode,
children,
} = props

const inputCodeRef = React.useRef(initialCode)
const editorRef = React.useRef(null)

const [monaco, setMonaco] = React.useState<Monaco>(null)
const [output, setOutput] = React.useState('')

async function runCode(code: string) {
const output = await onRunCode(code)
if (output) {
setOutput(output)
}
}

function handleEditorDidMount(editor: any, monaco: Monaco) {
editorRef.current = editor
setMonaco(monaco)
}

React.useEffect(() => {
if (!monaco || isLoading) {
return
}
const runCodeBinding: CustomKeyBinding = {
label: 'run',
keybinding: monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter,
callback: () => runCode(inputCodeRef.current),
editor: editorRef.current,
}
return addKeyBinding(runCodeBinding)
}, [monaco, isLoading])

return (
<>
<div>
<div>
<label className="block pb-4 text-sm font-medium text-gray-700 dark:text-gray-450">
{languageLabel}
</label>

<div className="mt-1 ">
<div className="relative group">
<div className="absolute -inset-0.5 dark:bg-gradient-to-r from-indigo-300 to-purple-400 rounded-lg blur opacity-25 group-hover:opacity-100 transition duration-1000 group-hover:duration-200 animate-tilt" />
<MonacoEditor
height="20rem"
defaultLanguage={defaultLanguage}
defaultValue={inputCodeRef.current}
onChange={(value) => {
inputCodeRef.current = value
}}
className="block w-1/2 text-white bg-gray-900 border-gray-300 rounded-lg shadow-sm p-0.5 border dark:border-purple-300 focus:ring-gray-500 focus:border-gray-500 sm:text-sm"
theme="vs-dark"
options={{ fontSize: 12 }}
onMount={handleEditorDidMount}
/>
</div>
</div>
</div>
</div>

<div className="pt-8 ">
<div className="grid items-start justify-left">
<div className="relative group">
<button
className="relative flex items-center py-4 leading-none bg-black divide-x divide-gray-600 rounded-lg px-7 border-gray-300 disabled:bg-gray-700 disabled:cursor-not-allowed"
onClick={() => runCode(inputCodeRef.current)}
disabled={isLoading}
>
<span className="text-gray-100 transition duration-200 group-hover:text-gray-100">
{!isLoading ? 'Run Code →' : `Loading ${languageLabel}...`}
</span>
</button>
</div>
</div>
</div>

{children}

{!hideOutputEditor && (
<div>
<label className="block pt-8 text-sm font-medium text-gray-700 dark:text-gray-450">
Output
</label>

<div className="mt-1 dark:text-gray-450">
<MonacoEditor
value={output?.toString()}
height="20rem"
defaultLanguage="python"
className="block w-1/2 text-white bg-gray-900 border-gray-300 rounded-lg shadow-sm p-0.5 border dark:border-purple-300 focus:ring-gray-500 focus:border-gray-500 sm:text-sm"
theme="vs-dark"
options={{ readOnly: true }}
/>
</div>
</div>
)}
</>
)
}

0 comments on commit 05117cd

Please sign in to comment.