Stub out story/controls and use code-mirror with vim for text-editing
This commit is contained in:
parent
c255e19c42
commit
6a0f95812a
11 changed files with 383 additions and 44 deletions
|
|
@ -31,8 +31,7 @@ import { Versions } from './versions';
|
|||
|
||||
declare const versions: Versions; // preload
|
||||
|
||||
const information = document.getElementById('info') as HTMLElement;
|
||||
information.innerText = `This app is using Chrome (v${versions.chrome()}), Node.js (v${versions.node()}), and Electron (v${versions.electron()})`;
|
||||
console.log(`This app is using Chrome (v${versions.chrome()}), Node.js (v${versions.node()}), and Electron (v${versions.electron()})`);
|
||||
|
||||
async function func() {
|
||||
const response = await versions.ping();
|
||||
|
|
|
|||
|
|
@ -1,26 +1,20 @@
|
|||
import { createSignal } from 'solid-js';
|
||||
import { ExprREPL } from './REPL';
|
||||
|
||||
function Hello() {
|
||||
const [ count, setCount ] = createSignal(0);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{ count() > 5 ? <span style={{ color: "red" }}>too damn high</span> : <span>{ count() }</span> }
|
||||
<div>
|
||||
<button onClick={ () => setCount((x: number) => x + 1) }>+</button>
|
||||
<button onClick={ () => setCount((x: number) => Math.max(x - 1, 0)) }>-</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
import { Story } from './Story';
|
||||
import { Controls } from './Controls';
|
||||
|
||||
export default function App() {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Hello />
|
||||
<ExprREPL />
|
||||
</div>
|
||||
<main
|
||||
class="container"
|
||||
style={{
|
||||
display: "grid",
|
||||
"grid-template-columns": "2fr 1fr",
|
||||
gap: "2rem",
|
||||
"margin-top": "2rem",
|
||||
}}
|
||||
>
|
||||
<Story />
|
||||
<Controls />
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
67
src/ui/CodeEditor.tsx
Normal file
67
src/ui/CodeEditor.tsx
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
import { onMount, onCleanup } from "solid-js";
|
||||
import { EditorView, basicSetup } from "codemirror";
|
||||
import { EditorState } from "@codemirror/state";
|
||||
import { oneDark } from "@codemirror/theme-one-dark";
|
||||
import { vim } from "@replit/codemirror-vim";
|
||||
|
||||
export interface EditorProps {
|
||||
value: string,
|
||||
onUpdate(val: string): void,
|
||||
onRun(): void,
|
||||
height?: string,
|
||||
}
|
||||
|
||||
export function CodeEditor(props: EditorProps) {
|
||||
let containerRef: HTMLDivElement | undefined;
|
||||
let view: EditorView;
|
||||
|
||||
const handleKeydown = (e: KeyboardEvent) => {
|
||||
if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
props.onRun();
|
||||
}
|
||||
};
|
||||
|
||||
onMount(() => {
|
||||
const themeConfig = EditorView.theme({
|
||||
"&": { height: props.height || "300px" },
|
||||
".cm-scroller": { overflow: "auto" }
|
||||
});
|
||||
|
||||
const state = EditorState.create({
|
||||
doc: props.value,
|
||||
extensions: [
|
||||
basicSetup,
|
||||
oneDark,
|
||||
vim(),
|
||||
themeConfig,
|
||||
EditorView.updateListener.of((update) => {
|
||||
if (update.docChanged) {
|
||||
props.onUpdate(update.state.doc.toString());
|
||||
}
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
view = new EditorView({
|
||||
state,
|
||||
parent: containerRef!,
|
||||
});
|
||||
|
||||
containerRef?.addEventListener("keydown", handleKeydown, { capture: true });
|
||||
});
|
||||
|
||||
onCleanup(() => {
|
||||
containerRef?.removeEventListener("keydown", handleKeydown, { capture: true });
|
||||
view.destroy()
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
class="editor-frame"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
34
src/ui/Controls.tsx
Normal file
34
src/ui/Controls.tsx
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
|
||||
type Props = {
|
||||
// TODO
|
||||
}
|
||||
|
||||
export function Controls(props: Props) {
|
||||
return (
|
||||
<aside
|
||||
style={{
|
||||
position: "sticky",
|
||||
top: "2rem",
|
||||
height: "fit-content"
|
||||
}}
|
||||
>
|
||||
<article>
|
||||
<header>Controls</header>
|
||||
|
||||
<fieldset>
|
||||
<label>
|
||||
<input type="checkbox" role="switch" checked />
|
||||
Auto-evaluate
|
||||
</label>
|
||||
<button class="secondary outline" style={{ width: "100%" }}>
|
||||
Clear All
|
||||
</button>
|
||||
</fieldset>
|
||||
|
||||
<footer>
|
||||
<small>Language v0.1.0</small>
|
||||
</footer>
|
||||
</article>
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import { SourceText, sourceText } from 'src/lang/parser/source_text';
|
|||
import { ParseError, parseExpr } from 'src/lang/parser/parser';
|
||||
import { ShowParseError } from './ParseError';
|
||||
import { Val } from './Value';
|
||||
import { CodeEditor } from './CodeEditor';
|
||||
|
||||
namespace ReplResult {
|
||||
export type Idle =
|
||||
|
|
@ -55,25 +56,15 @@ export function ExprREPL() {
|
|||
|
||||
return (
|
||||
<section>
|
||||
<textarea
|
||||
placeholder="+(3, 4)"
|
||||
rows="5"
|
||||
value={input()}
|
||||
onInput={(e) => setInput(e.currentTarget.value)}
|
||||
onKeyDown={(e) => {
|
||||
// Check for Enter + (Ctrl or Command for Mac)
|
||||
if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
|
||||
e.preventDefault(); // Stop the newline from being added
|
||||
runExecution();
|
||||
}
|
||||
}}
|
||||
<CodeEditor
|
||||
value={input()}
|
||||
onUpdate={setInput}
|
||||
onRun={runExecution}
|
||||
/>
|
||||
|
||||
<button onClick={runExecution}>Run</button>
|
||||
|
||||
<hr />
|
||||
|
||||
<div>
|
||||
<div style={{ "margin-top": "1rem" }}>
|
||||
<Switch>
|
||||
<Match when={result().tag === "idle"}>
|
||||
{ "" }
|
||||
|
|
|
|||
45
src/ui/Story.tsx
Normal file
45
src/ui/Story.tsx
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
import { ExprREPL } from "./REPL";
|
||||
|
||||
|
||||
type Props = {
|
||||
// TODO
|
||||
}
|
||||
|
||||
export function Story(props: Props) {
|
||||
return (
|
||||
<div
|
||||
id="story"
|
||||
style={{
|
||||
display: "flex",
|
||||
"flex-direction": "column",
|
||||
gap: "1.5rem",
|
||||
}}
|
||||
>
|
||||
<article>
|
||||
<header><strong>Interactive REPL</strong></header>
|
||||
<ExprREPL />
|
||||
</article>
|
||||
|
||||
<article>
|
||||
<header><strong>Header</strong></header>
|
||||
<p>This is a place for other items</p>
|
||||
</article>
|
||||
<article>
|
||||
<header><strong>Header</strong></header>
|
||||
<p>This is a place for other items</p>
|
||||
</article>
|
||||
<article>
|
||||
<header><strong>Header</strong></header>
|
||||
<p>This is a place for other items</p>
|
||||
</article>
|
||||
<article>
|
||||
<header><strong>Header</strong></header>
|
||||
<p>This is a place for other items</p>
|
||||
</article>
|
||||
<article>
|
||||
<header><strong>Header</strong></header>
|
||||
<p>This is a place for other items</p>
|
||||
</article>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,3 +1,37 @@
|
|||
@use "@picocss/pico/scss/pico";
|
||||
|
||||
// Custom styling goes here
|
||||
// ===Code-Mirror vim styling===
|
||||
.editor-frame {
|
||||
// Pico variable for cards, usually a slightly lighter dark grey
|
||||
background-color: var(--pico-card-background-color);
|
||||
border: 1px solid var(--pico-border-color);
|
||||
border-radius: var(--pico-border-radius);
|
||||
overflow: hidden; // Ensures the editor corners don't poke out
|
||||
margin-bottom: var(--pico-spacing);
|
||||
transition: border-color 0.2s ease-in-out;
|
||||
|
||||
&:focus-within {
|
||||
border-color: var(--pico-primary);
|
||||
box-shadow: 0 0 0 0.125rem rgba(var(--pico-primary-rgb), 0.25);
|
||||
}
|
||||
|
||||
// CodeMirror internal overrides
|
||||
.cm-editor {
|
||||
outline: none !important; // Remove default chrome/safari focus rings
|
||||
font-family: var(--pico-font-family-monospace);
|
||||
}
|
||||
|
||||
// Styling the Vim Command/Status Bar at the bottom
|
||||
.cm-vim-panel {
|
||||
background: #282c34 !important; // One Dark's background
|
||||
color: #abb2bf !important;
|
||||
border-top: 1px solid #181a1f;
|
||||
font-size: 0.8rem;
|
||||
padding: 4px 8px;
|
||||
|
||||
input {
|
||||
color: var(--pico-primary) !important;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import './index.scss';
|
|||
import { render } from 'solid-js/web';
|
||||
import { Program } from 'src/lang/program';
|
||||
import { ProgramProvider } from './ProgramProvider';
|
||||
// import App from './AppElm';
|
||||
import App from './App';
|
||||
|
||||
export function startApp() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue