cleanup CSS a bit
This commit is contained in:
parent
955bb17f9a
commit
dcd213102f
11 changed files with 113 additions and 79 deletions
|
|
@ -40,6 +40,11 @@ footer {
|
|||
color: white;
|
||||
}
|
||||
|
||||
footer ::selection {
|
||||
color: dodgerblue;
|
||||
background: lightblue;
|
||||
}
|
||||
|
||||
footer a {
|
||||
color: white;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,11 +142,35 @@ export function App() {
|
|||
// dynamic evalutions
|
||||
const evalResult = evalExpr(currentState, extendedEnv);
|
||||
|
||||
const onCopy = () => {
|
||||
const serialized = JSON.stringify(currentState);
|
||||
navigator.clipboard.write([new ClipboardItem({"text/plain": serialized})]);
|
||||
}
|
||||
const onPaste = () => {
|
||||
navigator.clipboard.read().then(items => {
|
||||
if (items.length === 1) {
|
||||
items[0].getType("text/plain")
|
||||
.then(value => value.text())
|
||||
.then(text => {
|
||||
try {
|
||||
const parsed = JSON.parse(text);
|
||||
pushHistory(_ => parsed);
|
||||
}
|
||||
catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<header>
|
||||
<button disabled={appState.history.length===1} onClick={onUndo}>Undo ({appState.history.length-1}) <kbd>Ctrl</kbd>+<kbd>Z</kbd></button>
|
||||
<button disabled={appState.future.length===0} onClick={onRedo}>Redo ({appState.future.length}) <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>Z</kbd></button>
|
||||
<button onClick={onCopy}>Copy <kbd>Ctrl</kbd>+<kbd>C</kbd></button>
|
||||
<button onClick={onPaste}>Paste <kbd>Ctrl</kbd>+<kbd>V</kbd></button>
|
||||
{
|
||||
actionShortcuts.map(([_, keys, descr], i) =>
|
||||
<span key={i} className={'command' + (highlighted[i] ? (' highlighted') : '')}>
|
||||
|
|
|
|||
|
|
@ -3,13 +3,11 @@
|
|||
position: relative;
|
||||
}
|
||||
.editor.error {
|
||||
border: 1px solid red;
|
||||
border: 1px solid red !important;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.errorMessage {
|
||||
display: none;
|
||||
position: absolute;
|
||||
color: darkred;
|
||||
background-color: pink;
|
||||
margin-top: 4px;
|
||||
|
|
@ -20,11 +18,6 @@
|
|||
width: max-content;
|
||||
}
|
||||
|
||||
.editor:hover > .errorMessage {
|
||||
display: block;
|
||||
/* z-index: 9999; */
|
||||
}
|
||||
|
||||
.editor.unknown {
|
||||
border: 1px dashed dodgerblue;
|
||||
display: inline-block;
|
||||
|
|
|
|||
|
|
@ -51,13 +51,14 @@ export function ExprBlock(props: ExprBlockProps) {
|
|||
const actions = getActions(globalContext, props.setState);
|
||||
const extraHandlers = Object.fromEntries(Object.entries(actions).map(([shortcut, action]) =>
|
||||
[shortcut, (e) => { e.preventDefault(); action(); }]));
|
||||
const err = props.typeInfo.err || evalExpr(props.state, env).err;
|
||||
return <span className={"editor" + (err ? " error" : "")}>
|
||||
const evalResult = evalExpr(props.state, env);
|
||||
const err = props.typeInfo.err || evalResult.err;
|
||||
return <span className={"editor" + (err ? " error" : "") + ((evalResult.val === undefined) ? " unknown" : "")}>
|
||||
{renderBlock[props.state.kind]()}
|
||||
{(err !== undefined) &&
|
||||
{/* {(err !== undefined) &&
|
||||
(<div className="errorMessage">
|
||||
{err.message.trim()}
|
||||
</div>)}
|
||||
</div>)} */}
|
||||
<Input
|
||||
placeholder="<c>"
|
||||
text=""
|
||||
|
|
|
|||
|
|
@ -1,32 +1,7 @@
|
|||
.inputBlock {
|
||||
position: relative;
|
||||
}
|
||||
.editable {
|
||||
position: relative;
|
||||
border: 0;
|
||||
font-size: 10pt;
|
||||
font-family: var(--my-monospace-font);
|
||||
background-color: transparent;
|
||||
color: inherit;
|
||||
padding: 0;
|
||||
cursor: text;
|
||||
outline: 0;
|
||||
}
|
||||
.suggest {
|
||||
top: 2.4px;
|
||||
position: absolute;
|
||||
color: #aaa;
|
||||
}
|
||||
.suggestionsPlaceholder {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
.suggestions {
|
||||
.suggestionsScrollableBox {
|
||||
display: block;
|
||||
color: black;
|
||||
text-align: left;
|
||||
position: absolute;
|
||||
border: solid 1px dodgerblue;
|
||||
cursor: pointer;
|
||||
max-height: calc(100vh - 64px);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { Type as TypeBlock, TypeInfoBlock } from "../other/Type";
|
|||
import type { ExprBlockState, State2Props } from "./ExprBlock";
|
||||
|
||||
import "./InputBlock.css";
|
||||
import { evalExpr } from "../../eval/eval";
|
||||
|
||||
interface Literal {
|
||||
kind: "literal";
|
||||
|
|
@ -95,7 +96,6 @@ export function InputBlock({ state, setState, score, onCancel, typeInfo }: Input
|
|||
const singleSuggestion = trie.growPrefix(env.names)(text);
|
||||
const suggestions = useMemo(() => computeSuggestions(text, env, score), [text, score, env]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (focus) {
|
||||
inputRef.current?.focus();
|
||||
|
|
@ -145,7 +145,10 @@ export function InputBlock({ state, setState, score, onCancel, typeInfo }: Input
|
|||
},
|
||||
};
|
||||
|
||||
return <><Input
|
||||
const err = typeInfo.err || evalExpr(state, env).err;
|
||||
|
||||
return <>
|
||||
<Input
|
||||
placeholder="<name or literal>"
|
||||
onCancel={onCancel}
|
||||
onEnter={onSelectSuggestion}
|
||||
|
|
@ -154,20 +157,26 @@ export function InputBlock({ state, setState, score, onCancel, typeInfo }: Input
|
|||
suggestion={singleSuggestion}
|
||||
extraHandlers={extraHandlers}
|
||||
>
|
||||
<span className="suggestionsPlaceholder">
|
||||
<span className="dropdownContainer">
|
||||
<span className="dropdown">
|
||||
{(err !== undefined) &&
|
||||
(<div className="errorMessage">
|
||||
{err.message.trim()}
|
||||
</div>)}
|
||||
<Suggestions
|
||||
suggestions={suggestions}
|
||||
onSelect={onSelectSuggestion}
|
||||
i={i} setI={setI} />
|
||||
</span>
|
||||
</span>
|
||||
</Input>
|
||||
::<TypeInfoBlock typeInfo={typeInfo} />
|
||||
</>
|
||||
</>;
|
||||
}
|
||||
|
||||
function Suggestions({ suggestions, onSelect, i, setI }) {
|
||||
return <>{(suggestions.length > 0) &&
|
||||
<div className={"suggestions"}>
|
||||
<div className={"suggestionsScrollableBox"}>
|
||||
{suggestions.map((suggestion, j) =>
|
||||
<SuggestionMemo key={j}
|
||||
{...{setI, j,
|
||||
|
|
|
|||
19
src/component/other/Input.css
Normal file
19
src/component/other/Input.css
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
.textboxContainer {
|
||||
position: relative;
|
||||
}
|
||||
.textbox {
|
||||
position: relative;
|
||||
border: 0;
|
||||
font-size: 10pt;
|
||||
font-family: var(--my-monospace-font);
|
||||
background-color: transparent;
|
||||
color: inherit;
|
||||
padding: 0;
|
||||
cursor: text;
|
||||
outline: 0;
|
||||
}
|
||||
.textbox.hint {
|
||||
top: 2.4px;
|
||||
position: absolute;
|
||||
color: #aaa;
|
||||
}
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
import { useEffect, useRef, type ReactNode, type KeyboardEvent, useState } from "react";
|
||||
|
||||
import "./Input.css";
|
||||
|
||||
interface InputProps {
|
||||
placeholder: string;
|
||||
text: string;
|
||||
|
|
@ -128,12 +130,11 @@ export function Input({placeholder, text, suggestion, onTextChange, onEnter, onC
|
|||
}
|
||||
};
|
||||
|
||||
return <span className="inputBlock">
|
||||
{(focus === "yes") && children}
|
||||
<span className="editable suggest">{text}{focus && suggestion}</span>
|
||||
return <span className="textboxContainer">
|
||||
<span className="textbox hint">{text}{focus && suggestion}</span>
|
||||
<input ref={ref}
|
||||
placeholder={placeholder}
|
||||
className="editable"
|
||||
className="textbox"
|
||||
value={text}
|
||||
onInput={(e) =>
|
||||
// @ts-ignore
|
||||
|
|
@ -143,5 +144,6 @@ export function Input({placeholder, text, suggestion, onTextChange, onEnter, onC
|
|||
onBlur={() => setFocus("no")}
|
||||
spellCheck={false}
|
||||
/>
|
||||
{(focus === "yes") && children}
|
||||
</span>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,13 +6,11 @@
|
|||
.type {
|
||||
margin:1px;
|
||||
display: inline-block;
|
||||
|
||||
font-family: "Roboto", sans-serif;
|
||||
font-optical-sizing: auto;
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-variation-settings: "wdth" 100;
|
||||
|
||||
color: darkgrey;
|
||||
}
|
||||
|
||||
|
|
@ -60,7 +58,7 @@
|
|||
|
||||
.iteratorType {
|
||||
border-style: dashed;
|
||||
/* animation: flickerAnimation 500ms steps(1) normal infinite; */
|
||||
animation: flickerAnimation 500ms steps(1) normal infinite;
|
||||
}
|
||||
|
||||
/* Animations */
|
||||
|
|
@ -74,25 +72,13 @@
|
|||
|
||||
.typeSignature {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.typeDebug {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.typeSignature:hover > .typeDebug {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
white-space-collapse: preserve;
|
||||
width: max-content;
|
||||
background-color: #d2ebf1e0;
|
||||
color: black;
|
||||
font-family: var(--my-monospace-font);
|
||||
padding: 4px;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.editor:hover > .typeSignature {
|
||||
display: inline-block;
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,10 +5,9 @@ import { ValueUnknown } from "./Value";
|
|||
import type { TypeInfo } from "../../eval/infer_type";
|
||||
|
||||
export function TypeInfoBlock({typeInfo}: {typeInfo: TypeInfo}) {
|
||||
return <span className="typeSignature gotDebug">
|
||||
return <span className="typeSignature mouseOver dropdownContainer">
|
||||
<Type type={typeInfo.type}/>
|
||||
<br/>
|
||||
<span className="typeDebug">{prettySS(typeInfo.subs)}</span>
|
||||
<span className="typeDebug hideIfMouseAway dropdown">{prettySS(typeInfo.subs)}</span>
|
||||
</span>;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,3 +17,24 @@ kbd {
|
|||
border-radius: 3px;
|
||||
margin: 0 2px 0 2px;
|
||||
}
|
||||
|
||||
|
||||
.dropdownContainer {
|
||||
position: relative;
|
||||
}
|
||||
.dropdown {
|
||||
position: absolute;
|
||||
display: block;
|
||||
z-index: 100;
|
||||
}
|
||||
.hideIfMouseAway {
|
||||
display: none;
|
||||
}
|
||||
.mouseOver:hover .dropdown {
|
||||
display: block;
|
||||
}
|
||||
|
||||
::selection {
|
||||
color: white;
|
||||
background: dodgerblue;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue