aboutsummaryrefslogtreecommitdiffstats
path: root/src/Editor.tsx
blob: afce38040a0ad2e204616f1a35d4ae3e7d92985b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import AceEditor from "react-ace"
import "ace-builds/src-noconflict/mode-java"
import "ace-builds/src-noconflict/theme-github"
import { useState } from "react"
import styles from "./Editor.module.css"
import { APIResult, submitSource, useExamples } from "./api"
import Select from "react-select"

const defaultSourceText = `define times2
    dup +
    ;

2 times2 .
-- prints 4
`

const Editor = () => {
  const examples = useExamples()
  const [sourceText, setSourceText] = useState(defaultSourceText)
  const [result, setResult] = useState<APIResult<string, Error>>({ type: "not_yet_requested" })
  const onChange = setSourceText

  const executeCode = async (text: string) => {
    const result = await submitSource(text)
    setResult(result)
  }

  const renderExamples = () => {
    switch (examples.type) {
      case "not_yet_requested":
      case "loading":
        return <div>Loading examples...</div>
      case "failed":
        return <div className={styles.error}>
          An unexpected error occurred while loading examples. See console for details.
        </div>
      case "success": {
        const options = examples.data.map(example => ({ value: example.content, label: example.title }))
        const customStyles = {
          option: (styles: any) => ({
            ...styles,
            cursor: "pointer",
          }),
          control: (styles: any) => ({
            ...styles,
            cursor: "pointer",
          }),
        }
        return (
          <Select
            placeholder="Pick an example code snippet..."
            options={options}
            onChange={(val) => { setSourceText(val?.value as string) }}
            styles={customStyles}
          />
        )
      }
    }
  }

  const renderResults = () => {
    switch (result.type) {
      case "not_yet_requested":
      case "loading":
        return null
      case "failed":
        return (
          <div className={styles.error}>
            Failed to run code on the server. See console for details.
          </div>
        )
      case "success":
        return (
          <AceEditor
            mode=""
            theme="github"
            onChange={() => undefined}
            value={result.data}
            name="results"
            editorProps={{ $blockScrolling: true }}
            width="100%"
            fontSize={16}
            readOnly
          />
        )
    }
  }

  return (
    <>
      <div className={styles.examples}>
        {renderExamples()}
      </div>
      <AceEditor
        mode=""
        theme="github"
        onChange={onChange}
        value={sourceText}
        name="editor"
        editorProps={{ $blockScrolling: true }}
        width="100%"
        fontSize={16}
      />
      <button className={styles.runButton} onClick={() => executeCode(sourceText)}>
        ▶️ Run code on server
      </button>
      <div className={styles.results}>
        {renderResults()}
      </div>
    </>
  )
}

export default Editor