Compare commits
17 Commits
e881102ade
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6db3dc65fa | ||
|
|
43d65b4fe3 | ||
|
|
ff3618b67d | ||
|
|
8c2c48a719 | ||
|
|
43de54039b | ||
|
|
acaf757ce3 | ||
|
|
1cc5dd7911 | ||
|
|
083b0aa376 | ||
|
|
d158fafd77 | ||
|
|
33ed9c4f56 | ||
|
|
a11201363e | ||
|
|
3b3ef70d3b | ||
|
|
6129bdad3e | ||
|
|
f89e62b9e1 | ||
|
|
5d31d50863 | ||
|
|
c2850fa879 | ||
|
|
d5020d3f24 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
|||||||
/node_modules/
|
/node_modules/
|
||||||
|
/dist/
|
||||||
|
|||||||
3
package-lock.json
generated
3
package-lock.json
generated
@@ -28,7 +28,8 @@
|
|||||||
"typescript": "^5.3.3",
|
"typescript": "^5.3.3",
|
||||||
"webpack": "^5.89.0",
|
"webpack": "^5.89.0",
|
||||||
"webpack-cli": "^5.1.4",
|
"webpack-cli": "^5.1.4",
|
||||||
"webpack-dev-server": "^4.15.1"
|
"webpack-dev-server": "^4.15.1",
|
||||||
|
"webpack-merge": "^5.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@ampproject/remapping": {
|
"node_modules/@ampproject/remapping": {
|
||||||
|
|||||||
@@ -4,8 +4,10 @@
|
|||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.jsx",
|
"main": "index.jsx",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "webpack server",
|
"dev": "webpack server --config webpack.dev.js",
|
||||||
"format": "prettier --write '**/*.{json,js,ts,tsx,css}'"
|
"format": "prettier --write '**/*.{json,js,ts,tsx,css}'",
|
||||||
|
"build": "webpack --config webpack.dev.js",
|
||||||
|
"release": "webpack --config webpack.prd.js"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
@@ -30,6 +32,7 @@
|
|||||||
"typescript": "^5.3.3",
|
"typescript": "^5.3.3",
|
||||||
"webpack": "^5.89.0",
|
"webpack": "^5.89.0",
|
||||||
"webpack-cli": "^5.1.4",
|
"webpack-cli": "^5.1.4",
|
||||||
"webpack-dev-server": "^4.15.1"
|
"webpack-dev-server": "^4.15.1",
|
||||||
|
"webpack-merge": "^5.10.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Editor from "./Editor";
|
import Explorer from "./Explorer";
|
||||||
import styles from "./App.module.css";
|
import styles from "./App.module.css";
|
||||||
import "./reset.css";
|
import "./reset.css";
|
||||||
|
|
||||||
function App({}) {
|
function App({}) {
|
||||||
return (
|
return (
|
||||||
<div className={styles.App}>
|
<div className={styles.App}>
|
||||||
<Editor />
|
<Explorer />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,19 @@
|
|||||||
.Editor {
|
.EditorTextWrapper {
|
||||||
display: flex;
|
--editor-background-color: #000000;
|
||||||
flex-direction: row;
|
--editor-font-color: #ffffff;
|
||||||
height: 100%;
|
--editor-highlight-color: #0000ff;
|
||||||
width: 100%;
|
}
|
||||||
|
@media (prefers-color-scheme: light) {
|
||||||
|
.EditorTextWrapper {
|
||||||
|
--editor-background-color: #ffffff;
|
||||||
|
--editor-font-color: #000000;
|
||||||
|
--editor-highlight-color: #ffff00;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.Editor-textwrapper {
|
.EditorTextWrapper {
|
||||||
flex: 1;
|
|
||||||
flex-basis: 0;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
background: white;
|
background: var(--editor-background-color);
|
||||||
font-family: ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas,
|
font-family: ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas,
|
||||||
"DejaVu Sans Mono", monospace;
|
"DejaVu Sans Mono", monospace;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
@@ -17,8 +21,9 @@
|
|||||||
text-align: initial;
|
text-align: initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Editor-textarea,
|
.EditorTextArea,
|
||||||
.Editor-underlay {
|
.EditorUnderlay {
|
||||||
|
color: var(--editor-font-color);
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
font-weight: inherit;
|
font-weight: inherit;
|
||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
@@ -28,7 +33,7 @@
|
|||||||
line-height: normal;
|
line-height: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Editor-textarea {
|
.EditorTextArea {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
@@ -43,7 +48,7 @@
|
|||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Editor-underlay {
|
.EditorUnderlay {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
@@ -52,7 +57,7 @@
|
|||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
|
|
||||||
.highlighted {
|
.EditorHighlighted {
|
||||||
background: #ffff00;
|
background: var(--editor-highlight-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
4
src/Editor.module.css.d.ts
vendored
Normal file
4
src/Editor.module.css.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export const EditorTextWrapper: string;
|
||||||
|
export const EditorTextArea: string;
|
||||||
|
export const EditorUnderlay: string;
|
||||||
|
export const EditorHighlighted: string;
|
||||||
@@ -1,68 +1,25 @@
|
|||||||
import React, { ReactNode, useMemo, useRef, useState } from "react";
|
import React, { useEffect, useRef } from "react";
|
||||||
import "./Editor.css";
|
|
||||||
import { Highlight } from "./highlight";
|
import { Highlight } from "./highlight";
|
||||||
import { buildShadow } from "./shadow";
|
import { buildShadow } from "./shadow";
|
||||||
import OrgAst, { OrgNodeReference } from "./OrgAst";
|
import styles from "./Editor.module.css";
|
||||||
import { parse_org } from "../../organic/target/wasm32-unknown-unknown/js/wasm";
|
|
||||||
|
|
||||||
const default_org_source: string = `Welcome to the Organic Ast Explorer!
|
interface EditorProps {
|
||||||
|
value: string;
|
||||||
Type your Org [fn:1] source in this text box, and it will be parsed by Organic [fn:2] that has been compiled into wasm and embedded in this page. The resulting AST will be rendered to the right.
|
setValue: Function;
|
||||||
|
highlights: Highlight[];
|
||||||
In the AST on the right, you can:
|
clearHighlights: Function;
|
||||||
|
}
|
||||||
1. Click on an AST node to highlight the corresponding portion of the Org source on the left.
|
function Editor({
|
||||||
2. Expand/Collapse the children, properties, and standard properties.
|
value,
|
||||||
|
setValue,
|
||||||
* Footnotes
|
highlights,
|
||||||
|
clearHighlights,
|
||||||
[fn:1] https://orgmode.org/
|
}: EditorProps): React.ReactNode {
|
||||||
|
|
||||||
[fn:2] https://code.fizz.buzz/talexander/organic
|
|
||||||
`;
|
|
||||||
|
|
||||||
function Editor({ defaultValue = default_org_source }) {
|
|
||||||
function handleChange(event: React.ChangeEvent<HTMLTextAreaElement>) {
|
function handleChange(event: React.ChangeEvent<HTMLTextAreaElement>) {
|
||||||
setValue(event.target.value);
|
setValue(event.target.value);
|
||||||
clearHighlights();
|
clearHighlights();
|
||||||
}
|
}
|
||||||
|
|
||||||
const [value, setValue] = useState(defaultValue);
|
|
||||||
|
|
||||||
const [highlights, setHighlights] = useState<Array<Highlight>>([]);
|
|
||||||
|
|
||||||
const astTree = useMemo(() => {
|
|
||||||
const astTree = parse_org(value);
|
|
||||||
console.log(JSON.stringify(astTree));
|
|
||||||
return astTree;
|
|
||||||
}, [value]);
|
|
||||||
|
|
||||||
function setHighlight(nodes: OrgNodeReference[]) {
|
|
||||||
let new_highlights = nodes.map((node: OrgNodeReference) => {
|
|
||||||
return new Highlight(node.start - 1, node.end - 1);
|
|
||||||
});
|
|
||||||
new_highlights.sort(function (a, b) {
|
|
||||||
if (a.start < b.start) return -1;
|
|
||||||
if (a.start > b.start) return 1;
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
setHighlights(new_highlights);
|
|
||||||
}
|
|
||||||
|
|
||||||
function addHighlight(start: number, end: number) {
|
|
||||||
let new_highlights = [...highlights, new Highlight(start, end)];
|
|
||||||
new_highlights.sort(function (a, b) {
|
|
||||||
if (a.start < b.start) return -1;
|
|
||||||
if (a.start > b.start) return 1;
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
setHighlights(new_highlights);
|
|
||||||
}
|
|
||||||
|
|
||||||
function clearHighlights() {
|
|
||||||
setHighlights([]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const textAreaRef = useRef<HTMLTextAreaElement>(null);
|
const textAreaRef = useRef<HTMLTextAreaElement>(null);
|
||||||
const shadowRef = useRef<HTMLDivElement>(null);
|
const shadowRef = useRef<HTMLDivElement>(null);
|
||||||
function onTextAreaScroll() {
|
function onTextAreaScroll() {
|
||||||
@@ -72,28 +29,26 @@ function Editor({ defaultValue = default_org_source }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Make sure the text area and shadow div start out in sync.
|
||||||
|
onTextAreaScroll();
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="Editor">
|
<div className={styles.EditorTextWrapper}>
|
||||||
<div className="Editor-textwrapper">
|
|
||||||
<textarea
|
<textarea
|
||||||
ref={textAreaRef}
|
ref={textAreaRef}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
className="Editor-textarea"
|
className={styles.EditorTextArea}
|
||||||
value={value}
|
value={value}
|
||||||
onScroll={onTextAreaScroll}
|
onScroll={onTextAreaScroll}
|
||||||
|
spellCheck={false}
|
||||||
/>
|
/>
|
||||||
<div ref={shadowRef} className="Editor-underlay">
|
<div ref={shadowRef} className={styles.EditorUnderlay}>
|
||||||
{buildShadow(highlights, value)}
|
{buildShadow(highlights, value)}
|
||||||
<br />
|
<br />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<OrgAst
|
|
||||||
setHighlight={setHighlight}
|
|
||||||
clearHighlights={clearHighlights}
|
|
||||||
value={value}
|
|
||||||
astTree={astTree}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
11
src/Explorer.module.css
Normal file
11
src/Explorer.module.css
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
.Explorer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
flex: 1;
|
||||||
|
flex-basis: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
1
src/Explorer.module.css.d.ts
vendored
Normal file
1
src/Explorer.module.css.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export const Explorer: string;
|
||||||
82
src/Explorer.tsx
Normal file
82
src/Explorer.tsx
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
import React, { useMemo, useState } from "react";
|
||||||
|
import styles from "./Explorer.module.css";
|
||||||
|
import { Highlight } from "./highlight";
|
||||||
|
import OrgAst, { OrgNodeReference } from "./OrgAst";
|
||||||
|
import { parse_org } from "../../organic/target/wasm32-unknown-unknown/js/wasm";
|
||||||
|
import Editor from "./Editor";
|
||||||
|
|
||||||
|
const default_org_source: string = `* Welcome to the Organic Ast Explorer!
|
||||||
|
|
||||||
|
Type your Org [fn:1] source in this text box, and it will be parsed by Organic [fn:2] that has been compiled into wasm and embedded in this page. The resulting AST will be rendered to the right.
|
||||||
|
|
||||||
|
In the AST on the right, you can:
|
||||||
|
|
||||||
|
1. Click on an AST node to highlight the corresponding portion of the Org source on the left.
|
||||||
|
2. Expand/Collapse the children, properties, and standard properties.
|
||||||
|
|
||||||
|
* Footnotes
|
||||||
|
|
||||||
|
[fn:1] https://orgmode.org/
|
||||||
|
|
||||||
|
[fn:2] https://code.fizz.buzz/talexander/organic
|
||||||
|
`;
|
||||||
|
|
||||||
|
interface ExplorerProps {
|
||||||
|
defaultValue?: string;
|
||||||
|
}
|
||||||
|
function Explorer({ defaultValue = default_org_source }: ExplorerProps) {
|
||||||
|
const [value, setValue] = useState(defaultValue);
|
||||||
|
|
||||||
|
const [highlights, setHighlights] = useState<Array<Highlight>>([]);
|
||||||
|
|
||||||
|
const astTree = useMemo(() => {
|
||||||
|
const astTree = parse_org(value);
|
||||||
|
console.log(JSON.stringify(astTree));
|
||||||
|
return astTree;
|
||||||
|
}, [value]);
|
||||||
|
|
||||||
|
function setHighlight(nodes: OrgNodeReference[]) {
|
||||||
|
let new_highlights = nodes.map((node: OrgNodeReference) => {
|
||||||
|
return new Highlight(node.start - 1, node.end - 1);
|
||||||
|
});
|
||||||
|
new_highlights.sort(function (a, b) {
|
||||||
|
if (a.start < b.start) return -1;
|
||||||
|
if (a.start > b.start) return 1;
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
setHighlights(new_highlights);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addHighlight(start: number, end: number) {
|
||||||
|
let new_highlights = [...highlights, new Highlight(start, end)];
|
||||||
|
new_highlights.sort(function (a, b) {
|
||||||
|
if (a.start < b.start) return -1;
|
||||||
|
if (a.start > b.start) return 1;
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
setHighlights(new_highlights);
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearHighlights() {
|
||||||
|
setHighlights([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.Explorer}>
|
||||||
|
<Editor
|
||||||
|
value={value}
|
||||||
|
setValue={setValue}
|
||||||
|
highlights={highlights}
|
||||||
|
clearHighlights={clearHighlights}
|
||||||
|
/>
|
||||||
|
<OrgAst
|
||||||
|
setHighlight={setHighlight}
|
||||||
|
clearHighlights={clearHighlights}
|
||||||
|
value={value}
|
||||||
|
astTree={astTree}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Explorer;
|
||||||
@@ -1,17 +1,57 @@
|
|||||||
.OrgAst {
|
.OrgAst {
|
||||||
flex: 1;
|
--ast-background-color: #111111;
|
||||||
background: #eeeeee;
|
--ast-font-color: #ffffff;
|
||||||
|
|
||||||
|
--ast-node-border-color: #bbbbbb;
|
||||||
|
--ast-node-shadow-color: #bbbbbb;
|
||||||
|
|
||||||
|
--ast-node-type-background-color: #933009;
|
||||||
|
--ast-node-type-hover-background-color: #8f0745;
|
||||||
|
--ast-node-type-selected-background-color: #630368;
|
||||||
|
|
||||||
|
--ast-node-subsection-border-color: #ffffff;
|
||||||
|
|
||||||
|
--ast-node-children-background-color: #111111;
|
||||||
|
|
||||||
|
--ast-node-table-row-odd-background-color: #111111;
|
||||||
|
--ast-node-table-row-even-background-color: #000000;
|
||||||
|
}
|
||||||
|
@media (prefers-color-scheme: light) {
|
||||||
|
.OrgAst {
|
||||||
|
--ast-background-color: #eeeeee;
|
||||||
|
--ast-font-color: #000000;
|
||||||
|
|
||||||
|
--ast-node-background-color: #ffffff;
|
||||||
|
--ast-node-border-color: #000000;
|
||||||
|
--ast-node-shadow-color: #000000;
|
||||||
|
|
||||||
|
--ast-node-type-background-color: #6ccff6;
|
||||||
|
--ast-node-type-hover-background-color: #70f8ba;
|
||||||
|
--ast-node-type-selected-background-color: #9cfc97;
|
||||||
|
|
||||||
|
--ast-node-subsection-border-color: #000000;
|
||||||
|
|
||||||
|
--ast-node-children-background-color: #eeeeee;
|
||||||
|
|
||||||
|
--ast-node-table-row-odd-background-color: #eeeeee;
|
||||||
|
--ast-node-table-row-even-background-color: #ffffff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.OrgAst {
|
||||||
|
background: var(--ast-background-color);
|
||||||
|
color: var(--ast-font-color);
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.OrgAstNode {
|
.OrgAstNode {
|
||||||
border: 1px solid #000000;
|
border: 1px solid var(--ast-node-border-color);
|
||||||
background: #ffffff;
|
background: var(--ast-node-background-color);
|
||||||
box-shadow: 3px 3px 4px #000000;
|
box-shadow: -3px 3px 1px var(--ast-node-shadow-color);
|
||||||
|
|
||||||
> details {
|
> details {
|
||||||
border: 1px solid #000000;
|
border: 1px solid var(--ast-node-subsection-border-color);
|
||||||
margin: 5px 5px 5px 2px;
|
margin: 5px 5px 5px 2px;
|
||||||
|
|
||||||
> summary {
|
> summary {
|
||||||
@@ -24,27 +64,28 @@
|
|||||||
> summary {
|
> summary {
|
||||||
border-width: 0 0 1px 0;
|
border-width: 0 0 1px 0;
|
||||||
border-style: dotted;
|
border-style: dotted;
|
||||||
border-color: #000000;
|
border-color: var(--ast-node-subsection-border-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.OrgAstNode.selected {
|
.OrgAstNode.selected {
|
||||||
> .OrgAstNodeType {
|
> .OrgAstNodeType {
|
||||||
background: #9cfc97;
|
background: var(--ast-node-type-selected-background-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.OrgAstNode.hovered:not(.selected) {
|
.OrgAstNode.hovered:not(.selected) {
|
||||||
> .OrgAstNodeType {
|
> .OrgAstNodeType {
|
||||||
background: #70f8ba;
|
background: var(--ast-node-type-hover-background-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.OrgAstNodeType {
|
.OrgAstNodeType {
|
||||||
background: #6ccff6;
|
background: var(--ast-node-type-background-color);
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
> span:first-child {
|
> span:first-child {
|
||||||
font-size: 1.1rem;
|
font-size: 1.1rem;
|
||||||
@@ -64,20 +105,20 @@
|
|||||||
|
|
||||||
.OrgAstChildren {
|
.OrgAstChildren {
|
||||||
padding: 5px 5px 5px 20px;
|
padding: 5px 5px 5px 20px;
|
||||||
background: #eeeeee;
|
background: var(--ast-node-children-background-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.OrgAstProperties,
|
.OrgAstProperties,
|
||||||
.OrgAstObjectTree,
|
.OrgAstObjectTree,
|
||||||
.OrgAstOptionalPair {
|
.OrgAstOptionalPair {
|
||||||
border: 1px solid #000000;
|
border: 1px solid var(--ast-node-subsection-border-color);
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
|
|
||||||
> tbody {
|
> tbody {
|
||||||
> tr {
|
> tr {
|
||||||
border-width: 1px 0;
|
border-width: 1px 0;
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
border-color: #000000;
|
border-color: var(--ast-node-subsection-border-color);
|
||||||
|
|
||||||
> th,
|
> th,
|
||||||
> td {
|
> td {
|
||||||
@@ -92,10 +133,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
> tr:nth-child(odd) {
|
> tr:nth-child(odd) {
|
||||||
background-color: #eeeeee;
|
background-color: var(--ast-node-table-row-odd-background-color);
|
||||||
}
|
}
|
||||||
> tr:nth-child(even) {
|
> tr:nth-child(even) {
|
||||||
background-color: #ffffff;
|
background-color: var(--ast-node-table-row-even-background-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,7 +144,7 @@
|
|||||||
.OrgAstObjectTree {
|
.OrgAstObjectTree {
|
||||||
> tbody {
|
> tbody {
|
||||||
border-style: dashed;
|
border-style: dashed;
|
||||||
border-color: #000000;
|
border-color: var(--ast-node-subsection-border-color);
|
||||||
}
|
}
|
||||||
> tbody:not(:first-child, :last-child) {
|
> tbody:not(:first-child, :last-child) {
|
||||||
border-width: 3px 0;
|
border-width: 3px 0;
|
||||||
|
|||||||
@@ -14,10 +14,18 @@ const OrgAst = (props: {
|
|||||||
const [hoveredNode, setHoveredNode] = useState<OrgNodeReference | null>(null);
|
const [hoveredNode, setHoveredNode] = useState<OrgNodeReference | null>(null);
|
||||||
|
|
||||||
function selectNode(uid: string, start: number, end: number) {
|
function selectNode(uid: string, start: number, end: number) {
|
||||||
|
if (selectedNode !== null && selectedNode.uid === uid) {
|
||||||
|
props.setHighlight([]);
|
||||||
|
setSelectedNode(null);
|
||||||
|
setHoveredNode(null);
|
||||||
|
} else {
|
||||||
const new_node: OrgNodeReference = { uid: uid, start: start, end: end };
|
const new_node: OrgNodeReference = { uid: uid, start: start, end: end };
|
||||||
props.setHighlight([new_node, hoveredNode].filter((node) => node !== null));
|
props.setHighlight(
|
||||||
|
[new_node, hoveredNode].filter((node) => node !== null),
|
||||||
|
);
|
||||||
setSelectedNode({ uid: uid, start: start, end: end });
|
setSelectedNode({ uid: uid, start: start, end: end });
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function startHoverNode(uid: string, start: number, end: number) {
|
function startHoverNode(uid: string, start: number, end: number) {
|
||||||
const new_node: OrgNodeReference = { uid: uid, start: start, end: end };
|
const new_node: OrgNodeReference = { uid: uid, start: start, end: end };
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React, { ReactNode, useState } from "react";
|
import React, { ReactNode } from "react";
|
||||||
import { Highlight } from "./highlight";
|
import { Highlight } from "./highlight";
|
||||||
|
import styles from "./Editor.module.css";
|
||||||
|
|
||||||
function buildShadow(highlights: Highlight[], text: string): ReactNode[] {
|
function buildShadow(highlights: Highlight[], text: string): ReactNode[] {
|
||||||
let output: ReactNode[] = [];
|
let output: ReactNode[] = [];
|
||||||
@@ -22,7 +23,7 @@ function buildShadow(highlights: Highlight[], text: string): ReactNode[] {
|
|||||||
} else if (state == ShadowState.Highlight && !thisCharHighlighted) {
|
} else if (state == ShadowState.Highlight && !thisCharHighlighted) {
|
||||||
// End the span
|
// End the span
|
||||||
output.push(
|
output.push(
|
||||||
<span key={i} className="highlighted">
|
<span key={i} className={styles.EditorHighlighted}>
|
||||||
{buffer}
|
{buffer}
|
||||||
</span>,
|
</span>,
|
||||||
);
|
);
|
||||||
@@ -37,7 +38,7 @@ function buildShadow(highlights: Highlight[], text: string): ReactNode[] {
|
|||||||
output.push(buffer);
|
output.push(buffer);
|
||||||
} else if (state == ShadowState.Highlight) {
|
} else if (state == ShadowState.Highlight) {
|
||||||
output.push(
|
output.push(
|
||||||
<span key={i} className="highlighted">
|
<span key={i} className={styles.EditorHighlighted}>
|
||||||
{buffer}
|
{buffer}
|
||||||
</span>,
|
</span>,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -75,8 +75,6 @@ module.exports = {
|
|||||||
filename: "index.html",
|
filename: "index.html",
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
mode: "development",
|
|
||||||
devtool: "inline-source-map",
|
|
||||||
experiments: {
|
experiments: {
|
||||||
asyncWebAssembly: true,
|
asyncWebAssembly: true,
|
||||||
},
|
},
|
||||||
7
webpack.dev.js
Normal file
7
webpack.dev.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
const { merge } = require("webpack-merge");
|
||||||
|
const common = require("./webpack.common.js");
|
||||||
|
|
||||||
|
module.exports = merge(common, {
|
||||||
|
mode: "development",
|
||||||
|
devtool: "inline-source-map",
|
||||||
|
});
|
||||||
6
webpack.prd.js
Normal file
6
webpack.prd.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
const { merge } = require("webpack-merge");
|
||||||
|
const common = require("./webpack.common.js");
|
||||||
|
|
||||||
|
module.exports = merge(common, {
|
||||||
|
mode: "production",
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user