aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/components/InputTypes/Code.tsx11
-rw-r--r--src/components/InputTypes/code/Code.tsx74
-rw-r--r--src/components/InputTypes/code/prism_css.tsx194
-rw-r--r--src/components/InputTypes/index.tsx8
4 files changed, 274 insertions, 13 deletions
diff --git a/src/components/InputTypes/Code.tsx b/src/components/InputTypes/Code.tsx
deleted file mode 100644
index 51ca98d..0000000
--- a/src/components/InputTypes/Code.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-/** @jsx jsx */
-import { jsx } from "@emotion/react";
-import React, { ChangeEvent } from "react";
-
-interface CodeProps {
- handler: (event: ChangeEvent<HTMLInputElement>) => void
-}
-
-export default function Code(props: CodeProps): JSX.Element {
- return <input type="text" className="text" onChange={props.handler}/>;
-}
diff --git a/src/components/InputTypes/code/Code.tsx b/src/components/InputTypes/code/Code.tsx
new file mode 100644
index 0000000..31b82f0
--- /dev/null
+++ b/src/components/InputTypes/code/Code.tsx
@@ -0,0 +1,74 @@
+/** @jsx jsx */
+import { jsx, css } from "@emotion/react";
+import React, { ChangeEvent } from "react";
+
+import prismStyles from "./prism_css";
+import Prism from 'prismjs';
+
+/**
+ * For supported languages, and language codes, see:
+ * https://prismjs.com/#supported-languages
+ */
+interface CodeProps {
+ handler: (event: ChangeEvent<HTMLInputElement>) => void,
+ language: string,
+}
+
+const blockStyles = css`
+ pre[class*="language-"] {
+ min-height: 20rem;
+ height: 100%;
+ width: 100%;
+ box-sizing: border-box;
+
+ resize: vertical;
+ padding: 1rem;
+ background: whitesmoke;
+
+ color: black;
+ font-family: Hind, Helvetica, Arial, sans-serif;
+
+ margin: auto;
+
+ border: 0.1rem solid black;
+ border-radius: 8px;
+ font-size: 1rem;
+ }
+`;
+
+const textareaStyles = css`
+ position: absolute;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ opacity: 0;
+ resize: none;
+
+ font-family: Hind, Helvetica, Arial, sans-serif;
+ padding: 1rem;
+ box-sizing: border-box;
+ font-size: 1rem;
+ border: 0.1rem solid transparent;
+ border-radius: 8px;
+`;
+
+export default class Code extends React.Component<CodeProps> {
+ constructor(props: CodeProps) {
+ super(props);
+ }
+
+ render() {
+ const ref: React.RefObject<HTMLInputElement> = React.createRef();
+ const placeholder = "print(\"hello world\")"
+
+ return <div css={[prismStyles, blockStyles, css`position: relative;`]}>
+ <pre className="language-js">
+ <code className="language-js" ref={ref}>{placeholder}</code>
+ </pre>
+ <textarea css={textareaStyles} onChange={event => {
+ ref.current!.textContent = event.target.value || placeholder;
+ Prism.highlightElement(ref.current!);
+ }}/>
+ </div>
+ }
+}
diff --git a/src/components/InputTypes/code/prism_css.tsx b/src/components/InputTypes/code/prism_css.tsx
new file mode 100644
index 0000000..7e45b41
--- /dev/null
+++ b/src/components/InputTypes/code/prism_css.tsx
@@ -0,0 +1,194 @@
+/* PrismJS 1.23.0
+https://prismjs.com/download.html#themes=prism&languages=python&plugins=line-numbers+autoloader+keep-markup+normalize-whitespace */
+/**
+ * prism.js default theme for JavaScript, CSS and HTML
+ * Based on dabblet (http://dabblet.com)
+ * @author Lea Verou
+ */
+
+/** @jsx jsx */
+import { css } from "@emotion/react";
+
+// Note: this file is a mostly unmodified version of the auto generated Prism CSS.
+// To update, you just need to paste the new css below, and update the link at the top.
+
+export default css`
+ code[class*="language-"],
+ pre[class*="language-"] {
+ color: black;
+ background: none;
+ text-shadow: 0 1px white;
+ font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
+ font-size: 1em;
+ text-align: left;
+ white-space: pre;
+ word-spacing: normal;
+ word-break: normal;
+ word-wrap: normal;
+ line-height: 1.5;
+
+ -moz-tab-size: 4;
+ -o-tab-size: 4;
+ tab-size: 4;
+
+ -webkit-hyphens: none;
+ -moz-hyphens: none;
+ -ms-hyphens: none;
+ hyphens: none;
+ }
+
+ pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
+ code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
+ text-shadow: none;
+ background: #b3d4fc;
+ }
+
+ pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
+ code[class*="language-"]::selection, code[class*="language-"] ::selection {
+ text-shadow: none;
+ background: #b3d4fc;
+ }
+
+ @media print {
+ code[class*="language-"],
+ pre[class*="language-"] {
+ text-shadow: none;
+ }
+ }
+
+ /* Code blocks */
+
+ pre[class*="language-"] {
+ padding: 1em;
+ margin: .5em 0;
+ overflow: auto;
+ }
+
+ :not(pre) > code[class*="language-"],
+ pre[class*="language-"] {
+ background: #f5f2f0;
+ }
+
+ /* Inline code */
+
+ :not(pre) > code[class*="language-"] {
+ padding: .1em;
+ border-radius: .3em;
+ white-space: normal;
+ }
+
+ .token.comment,
+ .token.prolog,
+ .token.doctype,
+ .token.cdata {
+ color: slategray;
+ }
+
+ .token.punctuation {
+ color: #999;
+ }
+
+ .token.namespace {
+ opacity: .7;
+ }
+
+ .token.property,
+ .token.tag,
+ .token.boolean,
+ .token.number,
+ .token.constant,
+ .token.symbol,
+ .token.deleted {
+ color: #905;
+ }
+
+ .token.selector,
+ .token.attr-name,
+ .token.string,
+ .token.char,
+ .token.builtin,
+ .token.inserted {
+ color: #690;
+ }
+
+ .token.operator,
+ .token.entity,
+ .token.url,
+ .language-css .token.string,
+ .style .token.string {
+ color: #9a6e3a;
+ /* This background color was intended by the author of this theme. */
+ background: hsla(0, 0%, 100%, .5);
+ }
+
+ .token.atrule,
+ .token.attr-value,
+ .token.keyword {
+ color: #07a;
+ }
+
+ .token.function,
+ .token.class-name {
+ color: #DD4A68;
+ }
+
+ .token.regex,
+ .token.important,
+ .token.variable {
+ color: #e90;
+ }
+
+ .token.important,
+ .token.bold {
+ font-weight: bold;
+ }
+
+ .token.italic {
+ font-style: italic;
+ }
+
+ .token.entity {
+ cursor: help;
+ }
+
+ pre[class*="language-"].line-numbers {
+ position: relative;
+ padding-left: 3.8em;
+ counter-reset: linenumber;
+ }
+
+ pre[class*="language-"].line-numbers > code {
+ position: relative;
+ white-space: inherit;
+ }
+
+ .line-numbers .line-numbers-rows {
+ position: absolute;
+ pointer-events: none;
+ top: 0;
+ font-size: 100%;
+ left: -3.8em;
+ width: 3em; /* works for line-numbers below 1000 lines */
+ letter-spacing: -1px;
+ border-right: 1px solid #999;
+
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+
+ }
+
+ .line-numbers-rows > span {
+ display: block;
+ counter-increment: linenumber;
+ }
+
+ .line-numbers-rows > span:before {
+ content: counter(linenumber);
+ color: #999;
+ display: block;
+ padding-right: 0.8em;
+ text-align: right;
+ }
+`;
diff --git a/src/components/InputTypes/index.tsx b/src/components/InputTypes/index.tsx
index bc65248..d624b96 100644
--- a/src/components/InputTypes/index.tsx
+++ b/src/components/InputTypes/index.tsx
@@ -1,5 +1,5 @@
import Checkbox from "./Checkbox";
-import Code from "./Code";
+import Code from "./code/Code";
import Radio from "./Radio";
import Range from "./Range";
import Select from "./Select";
@@ -25,6 +25,10 @@ export default function create_input({ question, public_state }: QuestionProp, h
// eslint-disable-next-line
// @ts-ignore
let options: string[] = question.data["options"];
+ // eslint-disable-next-line
+ // @ts-ignore
+ let language: string = question.data["language"] || "python";
+
let valid = true;
if (!public_state.get("valid")) {
valid = false;
@@ -64,7 +68,7 @@ export default function create_input({ question, public_state }: QuestionProp, h
case QuestionType.Code:
// TODO: Implement
- result = <Code handler={handler}/>;
+ result = <Code handler={handler} language={language}/>;
break;
default: