Skip to content
Snippets Groups Projects
Unverified Commit d6b8d489 authored by Louis's avatar Louis :fire:
Browse files

Add text editor, add reset button

parent 12f918ee
No related branches found
No related tags found
No related merge requests found
...@@ -1195,6 +1195,11 @@ ...@@ -1195,6 +1195,11 @@
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz",
"integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==" "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw=="
}, },
"@sphinxxxx/color-conversion": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@sphinxxxx/color-conversion/-/color-conversion-2.2.1.tgz",
"integrity": "sha512-5+ofCE09lF6C7DPSVyvQ2Nf0oaue3Cl+SosT45DYy5nhgUXsOq3TetArC1q8mVfAOjhG0WReQPPFBdc4xXVNkg=="
},
"@svgr/babel-plugin-add-jsx-attribute": { "@svgr/babel-plugin-add-jsx-attribute": {
"version": "4.2.0", "version": "4.2.0",
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz",
...@@ -2491,6 +2496,11 @@ ...@@ -2491,6 +2496,11 @@
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
}, },
"brace": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/brace/-/brace-0.11.1.tgz",
"integrity": "sha1-SJb8ydVE7vRfS7dmDbMg07N5/lg="
},
"brace-expansion": { "brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
...@@ -4379,6 +4389,11 @@ ...@@ -4379,6 +4389,11 @@
"resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-4.2.0.tgz", "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-4.2.0.tgz",
"integrity": "sha1-3vHxyl1gWdJKdm5YeULCEQbOEnU=" "integrity": "sha1-3vHxyl1gWdJKdm5YeULCEQbOEnU="
}, },
"drag-tracker": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/drag-tracker/-/drag-tracker-1.0.0.tgz",
"integrity": "sha1-m9M9OAvDBW22m9Wzz24GL+xYvWQ="
},
"duplexer": { "duplexer": {
"version": "0.1.1", "version": "0.1.1",
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
...@@ -6547,6 +6562,11 @@ ...@@ -6547,6 +6562,11 @@
"handlebars": "^4.1.2" "handlebars": "^4.1.2"
} }
}, },
"javascript-natural-sort": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz",
"integrity": "sha1-+eIwPUUH9tdDVac2ZNFED7Wg71k="
},
"jest": { "jest": {
"version": "24.7.1", "version": "24.7.1",
"resolved": "https://registry.npmjs.org/jest/-/jest-24.7.1.tgz", "resolved": "https://registry.npmjs.org/jest/-/jest-24.7.1.tgz",
...@@ -7581,6 +7601,11 @@ ...@@ -7581,6 +7601,11 @@
} }
} }
}, },
"jmespath": {
"version": "0.15.0",
"resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz",
"integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc="
},
"js-levenshtein": { "js-levenshtein": {
"version": "1.1.6", "version": "1.1.6",
"resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz",
...@@ -7670,6 +7695,11 @@ ...@@ -7670,6 +7695,11 @@
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
}, },
"json-source-map": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/json-source-map/-/json-source-map-0.4.0.tgz",
"integrity": "sha1-7qg3/jzi8r/VsTaHd5QGNUQjw1U="
},
"json-stable-stringify": { "json-stable-stringify": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
...@@ -7701,6 +7731,42 @@ ...@@ -7701,6 +7731,42 @@
"minimist": "^1.2.0" "minimist": "^1.2.0"
} }
}, },
"jsoneditor": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/jsoneditor/-/jsoneditor-6.1.0.tgz",
"integrity": "sha512-jZ5WUFqC+9MuYy5W7qz4VQa9xblfY1Xmzw79Odzz9pA6VyMRv7DIGvHLIzTOWl3KuWDQL/hsxliS6IBJeCev6Q==",
"requires": {
"ajv": "6.10.0",
"brace": "0.11.1",
"javascript-natural-sort": "0.7.1",
"jmespath": "0.15.0",
"json-source-map": "0.4.0",
"mobius1-selectr": "2.4.12",
"picomodal": "3.0.0",
"vanilla-picker": "2.8.1"
},
"dependencies": {
"ajv": {
"version": "6.10.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz",
"integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==",
"requires": {
"fast-deep-equal": "^2.0.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
}
}
}
},
"jsoneditor-react": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/jsoneditor-react/-/jsoneditor-react-1.0.1.tgz",
"integrity": "sha512-dfFavJi8MuAKi6vUVCRCoxghunS04mDwUzumqN25gl+yD/Db0gsHF+Nj4//QEVF/iSOe0b+sdmzin+5N5kldug==",
"requires": {
"prop-types": "^15.6.0"
}
},
"jsonfile": { "jsonfile": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
...@@ -8267,6 +8333,11 @@ ...@@ -8267,6 +8333,11 @@
} }
} }
}, },
"mobius1-selectr": {
"version": "2.4.12",
"resolved": "https://registry.npmjs.org/mobius1-selectr/-/mobius1-selectr-2.4.12.tgz",
"integrity": "sha512-zyGyhFaPCja2oHOud+9vOpLtIbIGv79jf0X1sfbBCCZ7UFHQIbx6yladAlyYU9Qq5zvsYw2Boa1CivSKvxLEHA=="
},
"move-concurrently": { "move-concurrently": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
...@@ -8921,6 +8992,11 @@ ...@@ -8921,6 +8992,11 @@
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
}, },
"picomodal": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/picomodal/-/picomodal-3.0.0.tgz",
"integrity": "sha1-+s0w9PvzSoCcHgTqUl8ATzmcC4I="
},
"pify": { "pify": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
...@@ -12183,6 +12259,15 @@ ...@@ -12183,6 +12259,15 @@
"spdx-expression-parse": "^3.0.0" "spdx-expression-parse": "^3.0.0"
} }
}, },
"vanilla-picker": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/vanilla-picker/-/vanilla-picker-2.8.1.tgz",
"integrity": "sha512-mzjMw0WbeS6qi+wzXSCfHFL7Jmvp7sJfXq0FfOvUEAAnCI6cmgCUVJ+wpr2c3g+Gt9AypLpHks3oeIkX6nCM9A==",
"requires": {
"@sphinxxxx/color-conversion": "^2.2.1",
"drag-tracker": "^1.0.0"
}
},
"vary": { "vary": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
......
...@@ -4,38 +4,73 @@ import Level from './render/Level' ...@@ -4,38 +4,73 @@ import Level from './render/Level'
import LevelData from './game/Level' import LevelData from './game/Level'
import testLevel from './data/testlevel1' import testLevel from './data/testlevel1'
import Editor from './editor/Editor'
class App extends Component<{}> { class App extends Component<{}> {
state = { state = {
margin: 0, margin: 0,
scale: 1.5, scale: 1.5,
showOptions: false, showOptions: false,
levelData: null rawLevelData: null,
levelData: null,
screen: 'editor',
}
componentDidMount() {
this.loadLevelData(testLevel)
} }
async componentDidMount() { async loadLevelData(data = this.state.rawLevelData) {
const levelData = await LevelData.from(testLevel) const levelData = await LevelData.from(data)
await levelData.tick() await levelData.tick()
this.setState({ levelData }) this.setState({ levelData, rawLevelData: data })
} }
render() { render() {
const { margin, scale, showOptions, levelData } = this.state const { margin, scale, showOptions, levelData } = this.state
const opts = {margin, scale} const opts = {margin, scale}
return ( return (
<React.Fragment> <React.Fragment>
<div className="render-controls" style={showOptions && {marginLeft: 0} || {}}> <div className="render-controls" style={showOptions && {marginLeft: 0} || {}}>
<div className="render-controls-row"><label>Margin: </label><input type="number" value={margin} <div className="render-controls-row">
onChange={this.set('margin')}/> <label>Margin: </label>
<input type="number" value={margin} onChange={this.set('margin')}/>
</div>
<div className="render-controls-row">
<label>Scale: </label>
<input type="number" value={scale} onChange={this.set('scale')} step={0.25}/>
</div> </div>
<div className="render-controls-row"><label>Scale: </label><input type="number" value={scale}
onChange={this.set('scale')}
step={0.25}/></div>
</div> </div>
<div className="root-container" style={showOptions && {marginLeft: 420} || {}}> <div className="root-container" style={showOptions && {marginLeft: 420} || {}}>
<button onClick={this.set('showOptions', s => !s.showOptions)}>{ showOptions ? 'Hide' : 'Show' } Options</button> <button onClick={this.set('showOptions', s => !s.showOptions)}>{ showOptions ? 'Hide' : 'Show' } Options</button>
<button onClick={this.set('screen', s => s.screen === 'editor' ? 'game' : 'editor')}>Toggle Editor</button>
<button onClick={() => this.loadLevelData()}>Reset Level</button>
<br/> <br/>
{ levelData == null ? <span>LOADING</span> : <Level level={levelData} {...opts} /> } {
(() => {
switch (this.state.screen) {
case 'game':
if (levelData == null) {
return <span>LOADING</span>
} else {
return <Level level={levelData} {...opts} />
}
case 'editor': {
return this.state.rawLevelData && (
<Editor
data={this.state.rawLevelData}
onChange={data => {
this.loadLevelData(data)
}}
/>
)
}
default:
return null
}
})()
}
</div> </div>
</React.Fragment> </React.Fragment>
); );
......
// @flow
import React from 'react'
import { range } from '../render/Level'
type Props = {
data: Object,
onChange: Function,
}
class Point extends React.PureComponent {
render() {
const { point: { x, y }, onChange } = this.props
return (
<div>
<label>X:</label><input type="number" value={x} onChange={e => onChange({ x: e.currentTarget.value, y })} />
<label>Y:</label><input type="number" value={y} onChange={e => onChange({ y: e.currentTarget.value, x })} />
</div>
)
}
}
class Section extends React.Component {
render() {
const { children, entries, onNew } = this.props
return entries.map(children)
}
}
class PointGrid extends React.PureComponent {
render() {
const { width, height, points, pointWidth = 10, pointHeight = 10, margin = 1, onChange } = this.props
const index = new Set()
const createKey = (x, y) => `${ x }|${ y }`
points.forEach(point => index.add(createKey(point.x, point.y)))
return (
<div style={{ width: width * pointWidth * margin, height: height * pointHeight * margin, position: 'relative' }}>
{ [...range(width)].map(x => (
[...range(height)].map(y => (
<div
style={{
position: 'absolute',
left: (x * pointWidth) + (margin * pointWidth),
top: (y * pointHeight) + (margin * pointHeight),
width: pointWidth,
height: pointHeight,
backgroundColor: index.has(createKey(x, y)) ? 'red' : 'grey'
}}
onClick={() => {
const alreadyActive = index.has(createKey(x, y))
if (alreadyActive) {
const index = points.findIndex(item => item.x === x && item.y === y)
const newPoints = [...points.slice(0, index), ...points.slice(index + 1)]
onChange(newPoints)
} else {
onChange(Array.from(points).concat([{ x, y }]))
}
}}
/>
))
))}
</div>
)
}
}
export default class Editor extends React.Component<Props> {
bindMerge = (mergefn) => {
return e => {
const value = e.currentTarget.value
const newData = { ...this.props.data }
mergefn(newData, value)
this.props.onChange(newData)
}
}
render() {
const { width, height, name, connectors, nouns, adjectives } = this.props.data
return (
<div>
<div>
Name: <input value={name} onChange={this.bindMerge((d, n) => d.name = n)} />
Width: <input value={width} onChange={this.bindMerge((d, n) => d.width = n)} type="number" />
Height: <input value={height} onChange={this.bindMerge((d, n) => d.height = n)} type="number" />
</div>
<h3>Connectors</h3>
<Section entries={connectors}>
{ (data, i) => (
<div key={i}>
<span>Type:</span><code>is</code>
<Point point={data} onChange={point => {
const data = { ...this.props.data }
data.connectors[i] = { ...point, type: 'is' }
this.props.onChange(data)
}} />
</div>
)}
</Section>
<h3>Nouns</h3>
<Section entries={nouns}>
{ (data, i) => (
<div key={i} style={{ border: '1px solid black', padding: '15px'}}>
<label>Name: </label><input value={data.name} />
<div style={{ display: 'flex', justifyContent: 'space-evenly', marginBottom: '20px' }}>
<div style={{ display: 'inline-block' }}>
<h4>Text</h4>
{ data.text_start_locations && <PointGrid width={width} height={height} points={data.text_start_locations} onChange={newList => {
const newData = {...this.props.data}
newData.nouns[i].text_start_locations = newList
this.props.onChange(newData)
}}/> }
</div>
<div style={{ display: 'inline-block' }}>
<h4>Entities</h4>
{ data.entity_start_locations && <PointGrid width={width} height={height} points={data.entity_start_locations} onChange={newList => {
const newData = {...this.props.data}
newData.nouns[i].entity_start_locations = newList
this.props.onChange(newData)
}}/> }
</div>
</div>
</div>
)}
</Section>
<h3>Adjectives</h3>
<Section entries={adjectives}>
{ (data, i) => (
<div key={i} style={{ border: '1px solid black', padding: '15px'}}>
<label>Name: </label><input value={data.name} />
<div style={{ display: 'flex', justifyContent: 'space-evenly', marginBottom: '20px' }}>
<div style={{ display: 'inline-block' }}>
<h4>Text</h4>
{ data.text_start_locations && <PointGrid width={width} height={height} points={data.text_start_locations} onChange={newList => {
const newData = {...this.props.data}
newData.adjectives[i].text_start_locations = newList
this.props.onChange(newData)
}}/> }
</div>
{/*<div style={{ display: 'inline-block' }}>*/}
{/* <h4>Entities</h4>*/}
{/* { data.entity_start_locations && <PointGrid width={width} height={height} points={data.entity_start_locations} /> }*/}
{/*</div>*/}
</div>
</div>
)}
</Section>
<pre><code>{ JSON.stringify(this.props.data, null, 2) }</code></pre>
</div>
)
}
}
\ No newline at end of file
...@@ -9,7 +9,7 @@ function* __rangeInner(start, end, step) { ...@@ -9,7 +9,7 @@ function* __rangeInner(start, end, step) {
} }
} }
function range(...args) { export function range(...args) {
if (args.length === 1) { if (args.length === 1) {
const [end] = args const [end] = args
return __rangeInner(0, end, 1) return __rangeInner(0, end, 1)
...@@ -40,12 +40,10 @@ export default class Level extends React.Component<Props> { ...@@ -40,12 +40,10 @@ export default class Level extends React.Component<Props> {
active: false, active: false,
} }
state = { state = {
nonce: Math.random(), nonce: Math.random(),
} }
componentDidMount(): void { componentDidMount(): void {
window.addEventListener('keyup', this.handleKeyPress) window.addEventListener('keyup', this.handleKeyPress)
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment