concept-collection / numbl-image-filter
numbl-image-filter / src / components / ScriptPanel.tsx
59 lines · 1.6 KBBlameHistoryRaw
1import { EXAMPLES } from "../examples.ts";
3interface Props {
4 script: string;
5 onChange: (s: string) => void;
6 onRun: () => void;
7 running: boolean;
8}
10export function ScriptPanel({ script, onChange, onRun, running }: Props) {
11 return (
12 <div className="script-panel">
13 <div className="script-toolbar">
14 <label className="field">
15 <span>Example</span>
16 <select
17 value=""
18 onChange={(e) => {
19 const ex = EXAMPLES.find((x) => x.name === e.target.value);
20 if (ex) onChange(ex.code);
21 e.target.value = "";
22 }}
23 >
24 <option value="" disabled>
25 Load an example…
26 </option>
27 {EXAMPLES.map((ex) => (
28 <option key={ex.name} value={ex.name}>
29 {ex.name}
30 </option>
31 ))}
32 </select>
33 </label>
35 <button className="run-btn" onClick={onRun} disabled={running}>
36 {running ? "Running…" : "Run ▶"}
37 </button>
38 </div>
40 <textarea
41 className="editor"
42 spellCheck={false}
43 value={script}
44 onChange={(e) => onChange(e.target.value)}
45 onKeyDown={(e) => {
46 if ((e.metaKey || e.ctrlKey) && e.key === "Enter") {
47 e.preventDefault();
48 onRun();
49 }
50 }}
51 />
52 <div className="editor-hint">
53 Define <code>out = filterImage(img)</code>. <code>img</code> is an{" "}
54 <code>H × W × 3</code> array of doubles in <code>[0, 255]</code> (RGB).
55 Press <kbd>⌘/Ctrl</kbd>+<kbd>Enter</kbd> to run.
56 </div>
57 </div>
58 );