the base logicGates page
This commit is contained in:
parent
c4883b9484
commit
8893967cb8
136
package-lock.json
generated
136
package-lock.json
generated
|
@ -1956,11 +1956,6 @@
|
||||||
"integrity": "sha512-8oe72N3WPMjA+2zVG71Ia0nXZ8DpQH+QyyHO+p06jT8eg8FGG3FbcUIi8KziHlAfheJQZeoqbvq1mQSQHXKYLw==",
|
"integrity": "sha512-8oe72N3WPMjA+2zVG71Ia0nXZ8DpQH+QyyHO+p06jT8eg8FGG3FbcUIi8KziHlAfheJQZeoqbvq1mQSQHXKYLw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"add-px-to-style": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/add-px-to-style/-/add-px-to-style-1.0.0.tgz",
|
|
||||||
"integrity": "sha1-0ME1RB+oAUqBN5BFMQlvZ/KPJjo="
|
|
||||||
},
|
|
||||||
"ajv": {
|
"ajv": {
|
||||||
"version": "6.10.0",
|
"version": "6.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz",
|
||||||
|
@ -3173,6 +3168,48 @@
|
||||||
"integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
|
"integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"copy-webpack-plugin": {
|
||||||
|
"version": "5.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.0.4.tgz",
|
||||||
|
"integrity": "sha512-YBuYGpSzoCHSSDGyHy6VJ7SHojKp6WHT4D7ItcQFNAYx2hrwkMe56e97xfVR0/ovDuMTrMffXUiltvQljtAGeg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"cacache": "^11.3.3",
|
||||||
|
"find-cache-dir": "^2.1.0",
|
||||||
|
"glob-parent": "^3.1.0",
|
||||||
|
"globby": "^7.1.1",
|
||||||
|
"is-glob": "^4.0.1",
|
||||||
|
"loader-utils": "^1.2.3",
|
||||||
|
"minimatch": "^3.0.4",
|
||||||
|
"normalize-path": "^3.0.0",
|
||||||
|
"p-limit": "^2.2.0",
|
||||||
|
"schema-utils": "^1.0.0",
|
||||||
|
"serialize-javascript": "^1.7.0",
|
||||||
|
"webpack-log": "^2.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"globby": {
|
||||||
|
"version": "7.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz",
|
||||||
|
"integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"array-union": "^1.0.1",
|
||||||
|
"dir-glob": "^2.0.0",
|
||||||
|
"glob": "^7.1.2",
|
||||||
|
"ignore": "^3.3.5",
|
||||||
|
"pify": "^3.0.0",
|
||||||
|
"slash": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pify": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
|
||||||
|
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"core-js": {
|
"core-js": {
|
||||||
"version": "2.6.9",
|
"version": "2.6.9",
|
||||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz",
|
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz",
|
||||||
|
@ -3739,6 +3776,32 @@
|
||||||
"randombytes": "^2.0.0"
|
"randombytes": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"dir-glob": {
|
||||||
|
"version": "2.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz",
|
||||||
|
"integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"path-type": "^3.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"path-type": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"pify": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pify": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
|
||||||
|
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"dns-equal": {
|
"dns-equal": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
|
||||||
|
@ -3773,16 +3836,6 @@
|
||||||
"utila": "~0.4"
|
"utila": "~0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dom-css": {
|
|
||||||
"version": "2.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/dom-css/-/dom-css-2.1.0.tgz",
|
|
||||||
"integrity": "sha1-/bwtWgFdCj4YcuEUcrvQ57nmogI=",
|
|
||||||
"requires": {
|
|
||||||
"add-px-to-style": "1.0.0",
|
|
||||||
"prefix-style": "2.0.1",
|
|
||||||
"to-camel-case": "1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"dom-helpers": {
|
"dom-helpers": {
|
||||||
"version": "3.4.0",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz",
|
||||||
|
@ -5880,6 +5933,12 @@
|
||||||
"integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=",
|
"integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"ignore": {
|
||||||
|
"version": "3.3.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz",
|
||||||
|
"integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"import-fresh": {
|
"import-fresh": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
|
||||||
|
@ -7722,7 +7781,8 @@
|
||||||
"performance-now": {
|
"performance-now": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"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=",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"pify": {
|
"pify": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
|
@ -8385,11 +8445,6 @@
|
||||||
"integrity": "sha512-ESPktioptiSUchCKgggAkzdmkgzKfmp0EU8jXH+5kbIUB+unr0Y4CY9SRMvibuvYUBjNh1ACLbxqYNpdTQOteQ==",
|
"integrity": "sha512-ESPktioptiSUchCKgggAkzdmkgzKfmp0EU8jXH+5kbIUB+unr0Y4CY9SRMvibuvYUBjNh1ACLbxqYNpdTQOteQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"prefix-style": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/prefix-style/-/prefix-style-2.0.1.tgz",
|
|
||||||
"integrity": "sha1-ZrupqHDP2jCKXcIOhekSCTLJWgY="
|
|
||||||
},
|
|
||||||
"prepend-http": {
|
"prepend-http": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
|
||||||
|
@ -8560,14 +8615,6 @@
|
||||||
"integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==",
|
"integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"raf": {
|
|
||||||
"version": "3.4.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
|
|
||||||
"integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
|
|
||||||
"requires": {
|
|
||||||
"performance-now": "^2.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"randombytes": {
|
"randombytes": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||||
|
@ -8621,16 +8668,6 @@
|
||||||
"scheduler": "^0.13.6"
|
"scheduler": "^0.13.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-custom-scrollbars": {
|
|
||||||
"version": "4.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-custom-scrollbars/-/react-custom-scrollbars-4.2.1.tgz",
|
|
||||||
"integrity": "sha1-gw/ZUCkn6X6KeMIIaBOJmyqLZts=",
|
|
||||||
"requires": {
|
|
||||||
"dom-css": "^2.0.0",
|
|
||||||
"prop-types": "^15.5.10",
|
|
||||||
"raf": "^3.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"react-dom": {
|
"react-dom": {
|
||||||
"version": "16.8.6",
|
"version": "16.8.6",
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.8.6.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.8.6.tgz",
|
||||||
|
@ -10243,25 +10280,12 @@
|
||||||
"integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=",
|
"integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"to-camel-case": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/to-camel-case/-/to-camel-case-1.0.0.tgz",
|
|
||||||
"integrity": "sha1-GlYFSy+daWKYzmamCJcyK29CPkY=",
|
|
||||||
"requires": {
|
|
||||||
"to-space-case": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"to-fast-properties": {
|
"to-fast-properties": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
|
||||||
"integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
|
"integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"to-no-case": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/to-no-case/-/to-no-case-1.0.2.tgz",
|
|
||||||
"integrity": "sha1-xyKQcWTvaxeBMsjmmTAhLRtKoWo="
|
|
||||||
},
|
|
||||||
"to-object-path": {
|
"to-object-path": {
|
||||||
"version": "0.3.0",
|
"version": "0.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
|
||||||
|
@ -10304,14 +10328,6 @@
|
||||||
"repeat-string": "^1.6.1"
|
"repeat-string": "^1.6.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"to-space-case": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/to-space-case/-/to-space-case-1.0.0.tgz",
|
|
||||||
"integrity": "sha1-sFLar7Gysp3HcM6gFj5ewOvJ/Bc=",
|
|
||||||
"requires": {
|
|
||||||
"to-no-case": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"toidentifier": {
|
"toidentifier": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
"dev": "webpack-dev-server --open --mode development",
|
"dev": "webpack-dev-server --open --mode development",
|
||||||
"build": "cross-env NODE_ENV=production webpack",
|
"build": "cross-env NODE_ENV=production webpack",
|
||||||
"build:server": "cross-env NODE_ENV=server webpack",
|
"build:server": "cross-env NODE_ENV=server webpack",
|
||||||
"deploy": "ts-node deploy",
|
|
||||||
"show": "gource -f --start-date \"2019-07-01 12:00\" --key --hide dirnames,filenames,bloom -s 0.3",
|
"show": "gource -f --start-date \"2019-07-01 12:00\" --key --hide dirnames,filenames,bloom -s 0.3",
|
||||||
"start": "node ./dist/server"
|
"start": "node ./dist/server"
|
||||||
},
|
},
|
||||||
|
@ -27,6 +26,7 @@
|
||||||
"babel-loader": "^8.0.6",
|
"babel-loader": "^8.0.6",
|
||||||
"babel-plugin-transform-runtime": "^6.23.0",
|
"babel-plugin-transform-runtime": "^6.23.0",
|
||||||
"babel-regenerator-runtime": "^6.5.0",
|
"babel-regenerator-runtime": "^6.5.0",
|
||||||
|
"copy-webpack-plugin": "^5.0.4",
|
||||||
"cross-env": "^5.2.0",
|
"cross-env": "^5.2.0",
|
||||||
"css-loader": "^3.0.0",
|
"css-loader": "^3.0.0",
|
||||||
"file-loader": "^4.1.0",
|
"file-loader": "^4.1.0",
|
||||||
|
@ -53,7 +53,6 @@
|
||||||
"keycode": "^2.2.0",
|
"keycode": "^2.2.0",
|
||||||
"mainloop.js": "^1.0.4",
|
"mainloop.js": "^1.0.4",
|
||||||
"react": "^16.8.6",
|
"react": "^16.8.6",
|
||||||
"react-custom-scrollbars": "^4.2.1",
|
|
||||||
"react-dom": "^16.8.6",
|
"react-dom": "^16.8.6",
|
||||||
"react-helmet": "^5.2.1",
|
"react-helmet": "^5.2.1",
|
||||||
"react-router-dom": "^5.0.1",
|
"react-router-dom": "^5.0.1",
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head> </head>
|
<head>
|
||||||
|
<!-- This doesnt work inside react helmetv-->
|
||||||
|
<meta name="pinterest" content="nopin" />
|
||||||
|
</head>
|
||||||
|
|
||||||
<body
|
<body
|
||||||
ondragstart="return false;"
|
ondragstart="return false;"
|
||||||
|
|
15
src/main.tsx
15
src/main.tsx
|
@ -6,18 +6,25 @@ import { handleErrors } from './modules/errors/helpers/handleErrors'
|
||||||
import { initKeyBindings } from './modules/keybindings/helpers/initialiseKeyBindings'
|
import { initKeyBindings } from './modules/keybindings/helpers/initialiseKeyBindings'
|
||||||
import { initBaseTemplates } from './modules/saving/helpers/initBaseTemplates'
|
import { initBaseTemplates } from './modules/saving/helpers/initBaseTemplates'
|
||||||
import { loadSubject } from './modules/core/subjects/loadedSubject'
|
import { loadSubject } from './modules/core/subjects/loadedSubject'
|
||||||
import { take } from 'rxjs/operators'
|
import { take, filter } from 'rxjs/operators'
|
||||||
import { logWelcome } from './modules/core/helpers/logWelcome'
|
import { logWelcome } from './modules/core/helpers/logWelcome'
|
||||||
|
import { initRenderer } from './modules/simulationRenderer/helpers/initRenderer'
|
||||||
|
import { updateLogicGateList } from './modules/logic-gates/subjects/LogicGateList'
|
||||||
|
|
||||||
export const start = async () => {
|
export const start = async () => {
|
||||||
console.clear()
|
const result = loadSubject
|
||||||
|
.pipe(
|
||||||
const result = loadSubject.pipe(take(1)).toPromise()
|
filter(a => a),
|
||||||
|
take(1)
|
||||||
|
)
|
||||||
|
.toPromise()
|
||||||
|
|
||||||
handleErrors()
|
handleErrors()
|
||||||
|
initRenderer()
|
||||||
initKeyBindings()
|
initKeyBindings()
|
||||||
initBaseTemplates()
|
initBaseTemplates()
|
||||||
logWelcome()
|
logWelcome()
|
||||||
|
updateLogicGateList()
|
||||||
|
|
||||||
render(<App />, document.getElementById('app'))
|
render(<App />, document.getElementById('app'))
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
@import '../styles/global-styles/global-styles.scss';
|
@import '../styles/global-styles/global-styles.scss';
|
||||||
|
@import '../../core/styles/mixins/full-screen.scss';
|
||||||
|
@import '../styles/colors.scss';
|
||||||
|
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
|
@ -8,7 +10,7 @@ body {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas {
|
.page {
|
||||||
background-color: #222222;
|
@include page-width();
|
||||||
z-index: -1;
|
background-color: $bg;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,33 +1,38 @@
|
||||||
import '../styles/reset'
|
import '../styles/reset'
|
||||||
import './App.scss'
|
import './App.scss'
|
||||||
|
import './Scrollbars.scss'
|
||||||
import 'react-toastify/dist/ReactToastify.css'
|
import 'react-toastify/dist/ReactToastify.css'
|
||||||
|
|
||||||
import { ToastContainer } from 'react-toastify'
|
import { ToastContainer } from 'react-toastify'
|
||||||
import { theme as muiTheme } from '../constants'
|
import { theme as muiTheme } from '../constants'
|
||||||
|
import { BrowserRouter as Router, Route, Link } from 'react-router-dom'
|
||||||
|
|
||||||
import React from 'react'
|
import React, { useEffect } from 'react'
|
||||||
import Canvas from './Canvas'
|
|
||||||
import CssBaseline from '@material-ui/core/CssBaseline'
|
import CssBaseline from '@material-ui/core/CssBaseline'
|
||||||
import Theme from '@material-ui/styles/ThemeProvider'
|
import Theme from '@material-ui/styles/ThemeProvider'
|
||||||
import Sidebar from './Sidebar'
|
import Sidebar from './Sidebar'
|
||||||
import CreateSimulation from '../../create-simulation/components/CreateSimulation'
|
|
||||||
import Input from '../../input/components/Input'
|
|
||||||
import LogicGateModal from '../../logic-gates/components/LogicGateModal'
|
|
||||||
import Head from './Head'
|
import Head from './Head'
|
||||||
|
import Root from './Root'
|
||||||
|
import LogicGatePage from '../../logic-gates/components/LogicGatesPage'
|
||||||
|
import { loadSubject } from '../subjects/loadedSubject'
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
|
useEffect(() => {
|
||||||
|
loadSubject.next(true)
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head />
|
<Head />
|
||||||
<CssBaseline />
|
<CssBaseline />
|
||||||
|
|
||||||
<Theme theme={muiTheme}>
|
<Theme theme={muiTheme}>
|
||||||
<CssBaseline />
|
<Router>
|
||||||
<Canvas />
|
<Sidebar />
|
||||||
<Sidebar />
|
|
||||||
<CreateSimulation />
|
<Route path="/" component={Root} exact />
|
||||||
<Input />
|
<Route path="/gates" component={LogicGatePage} />
|
||||||
<LogicGateModal />
|
</Router>
|
||||||
</Theme>
|
</Theme>
|
||||||
|
|
||||||
<ToastContainer
|
<ToastContainer
|
||||||
|
|
26
src/modules/core/components/BackToSimulation.tsx
Normal file
26
src/modules/core/components/BackToSimulation.tsx
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import React from 'react'
|
||||||
|
import ListItem from '@material-ui/core/ListItem'
|
||||||
|
import ListItemIcon from '@material-ui/core/ListItemIcon'
|
||||||
|
import ListItemText from '@material-ui/core/ListItemText'
|
||||||
|
import Icon from '@material-ui/core/Icon'
|
||||||
|
import { useTranslation } from '../../internalisation/helpers/useLanguage'
|
||||||
|
import { Link } from 'react-router-dom'
|
||||||
|
|
||||||
|
const BackToSimulation = () => {
|
||||||
|
const translation = useTranslation()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Link to="/">
|
||||||
|
<ListItem button className="contained">
|
||||||
|
<ListItemIcon>
|
||||||
|
<Icon>arrow_back_ios</Icon>
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText>
|
||||||
|
{translation.sidebar.backToSimulation}
|
||||||
|
</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BackToSimulation
|
|
@ -1,34 +1,30 @@
|
||||||
import React, { Component, createRef, Ref, RefObject } from 'react'
|
import React, { Component, createRef, RefObject } from 'react'
|
||||||
import FluidCanvas from './FluidCanvas'
|
import FluidCanvas from './FluidCanvas'
|
||||||
import loop from 'mainloop.js'
|
import loop from 'mainloop.js'
|
||||||
import { SimulationRenderer } from '../../simulationRenderer/classes/SimulationRenderer'
|
|
||||||
import { renderSimulation } from '../../simulationRenderer/helpers/renderSimulation'
|
import { renderSimulation } from '../../simulationRenderer/helpers/renderSimulation'
|
||||||
|
import { getRendererSafely } from '../../logic-gates/helpers/getRendererSafely'
|
||||||
|
import { Subscription } from 'rxjs'
|
||||||
import { rendererSubject } from '../subjects/rendererSubject'
|
import { rendererSubject } from '../subjects/rendererSubject'
|
||||||
import { loadSubject } from '../subjects/loadedSubject'
|
import { filter } from 'rxjs/operators'
|
||||||
|
|
||||||
class Canvas extends Component {
|
class Canvas extends Component {
|
||||||
private canvasRef: RefObject<HTMLCanvasElement> = createRef()
|
private canvasRef: RefObject<HTMLCanvasElement> = createRef()
|
||||||
private renderingContext: CanvasRenderingContext2D | null
|
private renderingContext: CanvasRenderingContext2D | null
|
||||||
private renderer = new SimulationRenderer(this.canvasRef)
|
|
||||||
|
|
||||||
public constructor(props: {}) {
|
public constructor(props: {}) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
rendererSubject.next(this.renderer)
|
|
||||||
|
|
||||||
loop.setDraw(() => {
|
loop.setDraw(() => {
|
||||||
if (this.renderingContext) {
|
if (this.renderingContext) {
|
||||||
renderSimulation(this.renderingContext, this.renderer)
|
renderSimulation(this.renderingContext, getRendererSafely())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentDidMount() {
|
public componentDidMount() {
|
||||||
loadSubject.next(true)
|
|
||||||
|
|
||||||
if (this.canvasRef.current) {
|
if (this.canvasRef.current) {
|
||||||
this.renderingContext = this.canvasRef.current.getContext('2d')
|
this.renderingContext = this.canvasRef.current.getContext('2d')
|
||||||
this.renderer.updateWheelListener()
|
getRendererSafely().updateWheelListener(this.canvasRef)
|
||||||
}
|
}
|
||||||
|
|
||||||
loop.start()
|
loop.start()
|
||||||
|
@ -39,12 +35,14 @@ class Canvas extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
|
const renderer = getRendererSafely()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FluidCanvas
|
<FluidCanvas
|
||||||
ref={this.canvasRef}
|
ref={this.canvasRef}
|
||||||
mouseDownOuput={this.renderer.mouseDownOutput}
|
mouseDownOuput={renderer.mouseDownOutput}
|
||||||
mouseUpOutput={this.renderer.mouseUpOutput}
|
mouseUpOutput={renderer.mouseUpOutput}
|
||||||
mouseMoveOutput={this.renderer.mouseMoveOutput}
|
mouseMoveOutput={renderer.mouseMoveOutput}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ const FluidCanvas = forwardRef(
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<canvas
|
<canvas
|
||||||
|
className="page"
|
||||||
ref={ref}
|
ref={ref}
|
||||||
width={currentWidth}
|
width={currentWidth}
|
||||||
height={currentHeight}
|
height={currentHeight}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import React from 'react'
|
||||||
const title = 'Logic gate simulator'
|
const title = 'Logic gate simulator'
|
||||||
const description = 'A logic gate simulator made for infoeducatie 2019'
|
const description = 'A logic gate simulator made for infoeducatie 2019'
|
||||||
const url = 'https://logic-gate-simulator.herokuapp.com/'
|
const url = 'https://logic-gate-simulator.herokuapp.com/'
|
||||||
const thumbail = require('../../../assets/thumbail.png')
|
const thumbail = require('../../../assets/favicon.ico')
|
||||||
|
|
||||||
const Head = () => {
|
const Head = () => {
|
||||||
return (
|
return (
|
||||||
|
@ -34,6 +34,11 @@ const Head = () => {
|
||||||
<meta property="og:image" content={`${url}${thumbail}`} />
|
<meta property="og:image" content={`${url}${thumbail}`} />
|
||||||
<meta property="og:url" content={url} />
|
<meta property="og:url" content={url} />
|
||||||
|
|
||||||
|
<meta
|
||||||
|
name="Description"
|
||||||
|
content="A logic gate simulator made for infoeducatie 2019"
|
||||||
|
/>
|
||||||
|
|
||||||
<link rel="icon" href={require('../../../assets/favicon.ico')} />
|
<link rel="icon" href={require('../../../assets/favicon.ico')} />
|
||||||
</Helmet>
|
</Helmet>
|
||||||
)
|
)
|
||||||
|
|
|
@ -4,8 +4,8 @@ import ListItemIcon from '@material-ui/core/ListItemIcon'
|
||||||
import ListItemText from '@material-ui/core/ListItemText'
|
import ListItemText from '@material-ui/core/ListItemText'
|
||||||
import Icon from '@material-ui/core/Icon'
|
import Icon from '@material-ui/core/Icon'
|
||||||
import { useTranslation } from '../../internalisation/helpers/useLanguage'
|
import { useTranslation } from '../../internalisation/helpers/useLanguage'
|
||||||
import { open } from '../../logic-gates/components/LogicGateModal'
|
|
||||||
import { updateLogicGateList } from '../../logic-gates/subjects/LogicGateList'
|
import { updateLogicGateList } from '../../logic-gates/subjects/LogicGateList'
|
||||||
|
import { Link } from 'react-router-dom'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component wich contains the sidebar 'Open simulation' button
|
* Component wich contains the sidebar 'Open simulation' button
|
||||||
|
@ -16,18 +16,19 @@ const LogicGates = () => {
|
||||||
const translation = useTranslation()
|
const translation = useTranslation()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ListItem
|
<Link to="/gates">
|
||||||
button
|
<ListItem
|
||||||
onClick={() => {
|
button
|
||||||
updateLogicGateList()
|
onClick={() => {
|
||||||
open.next(true)
|
updateLogicGateList()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<Icon>memory</Icon>
|
<Icon>memory</Icon>
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText>{translation.sidebar.logicGates}</ListItemText>
|
<ListItemText>{translation.sidebar.logicGates}</ListItemText>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
|
</Link>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
16
src/modules/core/components/Root.tsx
Normal file
16
src/modules/core/components/Root.tsx
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import React from 'react'
|
||||||
|
import Canvas from './Canvas'
|
||||||
|
import CreateSimulation from '../../create-simulation/components/CreateSimulation'
|
||||||
|
import Input from '../../input/components/Input'
|
||||||
|
|
||||||
|
const Root = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Canvas />
|
||||||
|
<CreateSimulation />
|
||||||
|
<Input />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Root
|
19
src/modules/core/components/Scrollbars.scss
Normal file
19
src/modules/core/components/Scrollbars.scss
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
/* width */
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Track */
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle */
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle on hover */
|
||||||
|
::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #555;
|
||||||
|
}
|
|
@ -7,6 +7,8 @@ import LogicGates from './LogicGates'
|
||||||
import { makeStyles, createStyles } from '@material-ui/core/styles'
|
import { makeStyles, createStyles } from '@material-ui/core/styles'
|
||||||
import Language from './Language'
|
import Language from './Language'
|
||||||
import SimulationActions from '../../simulation-actions/components/SimulationActions'
|
import SimulationActions from '../../simulation-actions/components/SimulationActions'
|
||||||
|
import { Route, Switch } from 'react-router'
|
||||||
|
import BackToSimulation from './BackToSimulation'
|
||||||
/**
|
/**
|
||||||
* The width of the sidebar
|
* The width of the sidebar
|
||||||
*/
|
*/
|
||||||
|
@ -56,11 +58,21 @@ const useStyles = makeStyles(
|
||||||
const Sidebar = () => {
|
const Sidebar = () => {
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
|
|
||||||
|
const rootSidebarContent = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<CreateSimulationButton />
|
||||||
|
<OpenSimulation />
|
||||||
|
<LogicGates />
|
||||||
|
<SimulationActions />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div className={classes.root}>
|
<div className={classes.root}>
|
||||||
<Drawer
|
<Drawer
|
||||||
className={classes.drawer}
|
className={classes.drawer}
|
||||||
variant="persistent"
|
variant={'persistent'}
|
||||||
anchor="right"
|
anchor="right"
|
||||||
open={true}
|
open={true}
|
||||||
classes={{
|
classes={{
|
||||||
|
@ -68,10 +80,10 @@ const Sidebar = () => {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<List component="nav" className={classes.list}>
|
<List component="nav" className={classes.list}>
|
||||||
<CreateSimulationButton />
|
<Switch>
|
||||||
<OpenSimulation />
|
<Route path="/" exact component={rootSidebarContent} />
|
||||||
<LogicGates />
|
<Route path="*" component={BackToSimulation} />
|
||||||
<SimulationActions />
|
</Switch>
|
||||||
</List>
|
</List>
|
||||||
|
|
||||||
<Language />
|
<Language />
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
$modal-bg-color: rgba(0, 0, 0, 0.7);
|
$modal-bg-color: rgba(0, 0, 0, 0.7);
|
||||||
$primary: #673ab7;
|
$primary: #673ab7;
|
||||||
$grey: #444444;
|
$grey: #444444;
|
||||||
|
$bg: #222222;
|
||||||
|
|
|
@ -5,3 +5,8 @@
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@mixin page-width {
|
||||||
|
@include full-screen();
|
||||||
|
width: calc(100% - 240px);
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
import { Subject } from 'rxjs'
|
import { BehaviorSubject } from 'rxjs'
|
||||||
|
|
||||||
export const loadSubject = new Subject<true>()
|
export const loadSubject = new BehaviorSubject(false)
|
||||||
|
|
|
@ -10,7 +10,8 @@ export const EnglishTranslation: Translation = {
|
||||||
logicGates: 'Logic gates',
|
logicGates: 'Logic gates',
|
||||||
openSimulation: 'Open simulations',
|
openSimulation: 'Open simulations',
|
||||||
simulation: 'Simulation',
|
simulation: 'Simulation',
|
||||||
language: 'Language'
|
language: 'Language',
|
||||||
|
backToSimulation: 'Back to simulation'
|
||||||
},
|
},
|
||||||
createSimulation: {
|
createSimulation: {
|
||||||
mode: {
|
mode: {
|
||||||
|
@ -42,6 +43,7 @@ export const EnglishTranslation: Translation = {
|
||||||
cleaned: name => `Succesfully cleaned simulation '${name}'`,
|
cleaned: name => `Succesfully cleaned simulation '${name}'`,
|
||||||
refreshed: name => `Succesfully refreshed simulation '${name}'`,
|
refreshed: name => `Succesfully refreshed simulation '${name}'`,
|
||||||
undone: name => `Succesfully undone simulation '${name}'`,
|
undone: name => `Succesfully undone simulation '${name}'`,
|
||||||
deletedSimulation: name => `Succesfully deleted simulation '${name}'`
|
deletedSimulation: name => `Succesfully deleted simulation '${name}'`,
|
||||||
|
addedGate: name => `Succesfully added gate '${name}'`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,8 @@ export const DutchTranslation: Translation = {
|
||||||
logicGates: 'Logische poorten',
|
logicGates: 'Logische poorten',
|
||||||
openSimulation: 'Open simulatie',
|
openSimulation: 'Open simulatie',
|
||||||
simulation: 'Todo',
|
simulation: 'Todo',
|
||||||
language: 'Taal'
|
language: 'Taal',
|
||||||
|
backToSimulation: 'Todo'
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
'delete selection': 'Todo',
|
'delete selection': 'Todo',
|
||||||
|
|
|
@ -10,7 +10,8 @@ export const RomanianTranslation: Translation = {
|
||||||
openSimulation: 'Deschide o simulație',
|
openSimulation: 'Deschide o simulație',
|
||||||
logicGates: 'Porți logice',
|
logicGates: 'Porți logice',
|
||||||
simulation: 'Simulație',
|
simulation: 'Simulație',
|
||||||
language: 'Limba'
|
language: 'Limba',
|
||||||
|
backToSimulation: 'Înapoi la simulație'
|
||||||
},
|
},
|
||||||
createSimulation: {
|
createSimulation: {
|
||||||
mode: {
|
mode: {
|
||||||
|
@ -44,6 +45,7 @@ export const RomanianTranslation: Translation = {
|
||||||
refreshed: name => `Simulația '${name}' a fost reîncărcată cu succes`,
|
refreshed: name => `Simulația '${name}' a fost reîncărcată cu succes`,
|
||||||
undone: name => `Acțiunea a fost întoarsă`,
|
undone: name => `Acțiunea a fost întoarsă`,
|
||||||
deletedSimulation: name =>
|
deletedSimulation: name =>
|
||||||
`Simulația '${name}' a fost ștearsă cu succes`
|
`Simulația '${name}' a fost ștearsă cu succes`,
|
||||||
|
addedGate: name => `Componentul '${name}' a fost adăugat cu succes`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ export interface Translation {
|
||||||
logicGates: string
|
logicGates: string
|
||||||
simulation: string
|
simulation: string
|
||||||
language: string
|
language: string
|
||||||
|
backToSimulation: string
|
||||||
}
|
}
|
||||||
createSimulation: {
|
createSimulation: {
|
||||||
mode: {
|
mode: {
|
||||||
|
@ -35,6 +36,7 @@ export interface Translation {
|
||||||
cleaned: NameSentence
|
cleaned: NameSentence
|
||||||
undone: NameSentence
|
undone: NameSentence
|
||||||
deletedSimulation: NameSentence
|
deletedSimulation: NameSentence
|
||||||
|
addedGate: NameSentence
|
||||||
}
|
}
|
||||||
actions: Record<possibleAction, string>
|
actions: Record<possibleAction, string>
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ export const initKeyBindings = (bindings: KeyBindingMap = keyBindings) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('keydown', e => {
|
window.addEventListener('keydown', e => {
|
||||||
if (!modalIsOpen()) {
|
if (!modalIsOpen() && location.pathname === '/') {
|
||||||
const current: {
|
const current: {
|
||||||
keys: string[]
|
keys: string[]
|
||||||
callback: Function
|
callback: Function
|
||||||
|
|
22
src/modules/logic-gates/components/AddGate.tsx
Normal file
22
src/modules/logic-gates/components/AddGate.tsx
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import React from 'react'
|
||||||
|
import Icon from '@material-ui/core/Icon'
|
||||||
|
import IconButton from '@material-ui/core/IconButton'
|
||||||
|
import { LogicGateProps } from './LogicGate'
|
||||||
|
import { addGateFromTemplate } from '../helpers/addGateFromTemplate'
|
||||||
|
|
||||||
|
const AddGate = ({ template }: LogicGateProps) => {
|
||||||
|
return (
|
||||||
|
<div className="gate-info-icon">
|
||||||
|
<IconButton
|
||||||
|
aria-label="add"
|
||||||
|
onClick={() => {
|
||||||
|
addGateFromTemplate(template)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon>add</Icon>
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AddGate
|
25
src/modules/logic-gates/components/GateInfo.tsx
Normal file
25
src/modules/logic-gates/components/GateInfo.tsx
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import React from 'react'
|
||||||
|
import Icon from '@material-ui/core/Icon'
|
||||||
|
import IconButton from '@material-ui/core/IconButton'
|
||||||
|
import { LogicGateProps } from './LogicGate'
|
||||||
|
import { randomItem } from '../../internalisation/helpers/randomItem'
|
||||||
|
|
||||||
|
const GateInfo = ({ template }: LogicGateProps) => {
|
||||||
|
const info = template.info
|
||||||
|
|
||||||
|
if (info.length === 0) {
|
||||||
|
return <></>
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<div className="gate-info-icon">
|
||||||
|
<a href={randomItem(info)} target="blank">
|
||||||
|
<IconButton aria-label="info">
|
||||||
|
<Icon>info</Icon>
|
||||||
|
</IconButton>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GateInfo
|
19
src/modules/logic-gates/components/GateSettings.tsx
Normal file
19
src/modules/logic-gates/components/GateSettings.tsx
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import React from 'react'
|
||||||
|
import Icon from '@material-ui/core/Icon'
|
||||||
|
import { LogicGateProps } from './LogicGate'
|
||||||
|
|
||||||
|
const GateSettings = ({ template }: LogicGateProps) => {
|
||||||
|
const tags = template.tags
|
||||||
|
|
||||||
|
if (tags.includes('base')) {
|
||||||
|
return <></>
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<div className="gate-info-icon">
|
||||||
|
<Icon>settings</Icon>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GateSettings
|
31
src/modules/logic-gates/components/LogicGate.scss
Normal file
31
src/modules/logic-gates/components/LogicGate.scss
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
@import '../../core/styles/mixins/flex.scss';
|
||||||
|
|
||||||
|
$gate-margin: 1em;
|
||||||
|
|
||||||
|
.gate > section > .gate-preview > * {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gate > section > .gate-preview > * {
|
||||||
|
display: block;
|
||||||
|
height: 10em;
|
||||||
|
width: 10em;
|
||||||
|
|
||||||
|
margin: $gate-margin;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gate > section > .gate-name {
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gate > section > .gate-icons {
|
||||||
|
@include flex();
|
||||||
|
|
||||||
|
width: calc(100% - 2 * #{$gate-margin});
|
||||||
|
height: 100%;
|
||||||
|
margin: $gate-margin;
|
||||||
|
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
}
|
46
src/modules/logic-gates/components/LogicGate.tsx
Normal file
46
src/modules/logic-gates/components/LogicGate.tsx
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
import './LogicGate.scss'
|
||||||
|
import React from 'react'
|
||||||
|
import { GateTemplate } from '../../simulation/types/GateTemplate'
|
||||||
|
import GateInfo from './GateInfo'
|
||||||
|
import GateSettings from './GateSettings'
|
||||||
|
import AddGate from './AddGate'
|
||||||
|
|
||||||
|
export interface LogicGateProps {
|
||||||
|
template: GateTemplate
|
||||||
|
}
|
||||||
|
|
||||||
|
const LogicGate = ({ template }: LogicGateProps) => {
|
||||||
|
const gatePreview =
|
||||||
|
template.material.type === 'image' ? (
|
||||||
|
<img src={template.material.fill} alt={template.metadata.name} />
|
||||||
|
) : (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
backgroundColor: template.material.fill
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
|
||||||
|
const rawName = template.metadata.name
|
||||||
|
const name = `${rawName[0].toUpperCase()}${rawName.substr(1)}`
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="gate">
|
||||||
|
<section>
|
||||||
|
<div className="gate-preview">{gatePreview}</div>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<div className="gate-name">{name}</div>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<div className="gate-icons">
|
||||||
|
<GateInfo template={template} />
|
||||||
|
<GateSettings template={template} />
|
||||||
|
<AddGate template={template} />
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LogicGate
|
|
@ -1,70 +0,0 @@
|
||||||
@import '../../core/styles/mixins/flex.scss';
|
|
||||||
@import '../../core/styles/mixins/visibility.scss';
|
|
||||||
@import '../../modals/styles/mixins/modal-container.scss';
|
|
||||||
@import '../../modals/styles/mixins/modal-title.scss';
|
|
||||||
@import '../../core/styles/colors.scss';
|
|
||||||
@import '../../core/styles/mixins/glow.scss';
|
|
||||||
|
|
||||||
// Opacities
|
|
||||||
$normal-opacity: 0.6;
|
|
||||||
$hover-opacity: 0.9;
|
|
||||||
|
|
||||||
// Colors
|
|
||||||
$item-color: $grey;
|
|
||||||
|
|
||||||
#logic-gate-modal-container {
|
|
||||||
@include modal-container();
|
|
||||||
|
|
||||||
justify-content: center;
|
|
||||||
overflow-y: auto;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.visible#logic-gate-modal-container {
|
|
||||||
@include visible();
|
|
||||||
}
|
|
||||||
|
|
||||||
#logic-gate-modal-container > .logic-gate-item {
|
|
||||||
@include flex();
|
|
||||||
|
|
||||||
justify-content: left;
|
|
||||||
flex-direction: row;
|
|
||||||
|
|
||||||
width: 80%;
|
|
||||||
height: 4em;
|
|
||||||
|
|
||||||
border: 3px solid white;
|
|
||||||
margin: 0.5em;
|
|
||||||
|
|
||||||
background-color: rgba($item-color, $normal-opacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
#logic-gate-modal-container > .logic-gate-item:hover {
|
|
||||||
background-color: rgba($item-color, $hover-opacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
#logic-gate-modal-container > .logic-gate-item > * {
|
|
||||||
font-size: 2.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#logic-gate-modal-container > .logic-gate-item > .logic-gate-item-type {
|
|
||||||
margin: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#logic-gate-modal-container > .logic-gate-item > *:last-child {
|
|
||||||
margin-right: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lgi-icon:hover:not(.logic-gate-item-type) {
|
|
||||||
border: 1px solid white;
|
|
||||||
}
|
|
||||||
|
|
||||||
#logic-gate-modal-container > .logic-gate-item > .logic-gate-item-name {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#logic-gate-modal-container > .logic-gate-item:first-child {
|
|
||||||
// height: 4em;
|
|
||||||
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
|
@ -1,90 +0,0 @@
|
||||||
import './LogicGateModal.scss'
|
|
||||||
import React from 'react'
|
|
||||||
import { BehaviorSubject } from 'rxjs'
|
|
||||||
import { useObservable } from 'rxjs-hooks'
|
|
||||||
import { LogicGateList } from '../subjects/LogicGateList'
|
|
||||||
import Icon from '@material-ui/core/Icon'
|
|
||||||
import Typography from '@material-ui/core/Typography'
|
|
||||||
import { addGate } from '../../simulation/helpers/addGate'
|
|
||||||
import { randomItem } from '../../internalisation/helpers/randomItem'
|
|
||||||
import { gateIcons } from '../constants'
|
|
||||||
import { getTemplateSafely } from '../helpers/getTemplateSafely'
|
|
||||||
import { getRendererSafely } from '../helpers/getRendererSafely'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subject containing the open state of the modal
|
|
||||||
*/
|
|
||||||
export const open = new BehaviorSubject(false)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* helper to close the modal
|
|
||||||
*/
|
|
||||||
export const handleClose = () => {
|
|
||||||
open.next(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The component containing the info / actions about all logic gates
|
|
||||||
*/
|
|
||||||
const LogicGateModal = () => {
|
|
||||||
const openSnapshot = useObservable(() => open, false)
|
|
||||||
const gates = useObservable(() => LogicGateList, [])
|
|
||||||
const renderer = getRendererSafely()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={openSnapshot ? 'visible' : ''}
|
|
||||||
id="logic-gate-modal-container"
|
|
||||||
onClick={handleClose}
|
|
||||||
>
|
|
||||||
<div className="logic-gate-item">---</div>
|
|
||||||
{gates
|
|
||||||
.map(getTemplateSafely)
|
|
||||||
.filter(template => {
|
|
||||||
return (
|
|
||||||
renderer.simulation.mode === 'project' ||
|
|
||||||
template.metadata.name !== renderer.simulation.name
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.map((template, index) => {
|
|
||||||
const { name } = template.metadata
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={index}
|
|
||||||
className="logic-gate-item"
|
|
||||||
onClick={e => {
|
|
||||||
addGate(renderer, name)
|
|
||||||
|
|
||||||
e.stopPropagation()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Icon className="lgi-icon logic-gate-item-type">
|
|
||||||
{gateIcons[template.tags[0]]}
|
|
||||||
</Icon>
|
|
||||||
<Typography className="logic-gate-item-name">
|
|
||||||
{name}
|
|
||||||
</Typography>
|
|
||||||
{template.info.length ? (
|
|
||||||
<a
|
|
||||||
target="_blank"
|
|
||||||
className="logic-gate-item-info"
|
|
||||||
href={randomItem(template.info)}
|
|
||||||
onClick={e => {
|
|
||||||
e.stopPropagation()
|
|
||||||
// e.preventDefault()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Icon className="lgi-icon">info</Icon>
|
|
||||||
</a>
|
|
||||||
) : (
|
|
||||||
''
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default LogicGateModal
|
|
34
src/modules/logic-gates/components/LogicGatesPage.scss
Normal file
34
src/modules/logic-gates/components/LogicGatesPage.scss
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
@import '../../core/styles/colors.scss';
|
||||||
|
@import '../../core/styles/mixins/flex.scss';
|
||||||
|
|
||||||
|
#gates-page {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gate-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
|
||||||
|
grid-auto-rows: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gate-grid::before {
|
||||||
|
content: '';
|
||||||
|
width: 0;
|
||||||
|
padding-bottom: 100%;
|
||||||
|
grid-row: 1 / 1;
|
||||||
|
grid-column: 1 / 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gate-grid > *:first-child {
|
||||||
|
grid-row: 1 / 1;
|
||||||
|
grid-column: 1 / 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gate-grid > * {
|
||||||
|
@include flex();
|
||||||
|
|
||||||
|
justify-content: start;
|
||||||
|
margin: 0.3em;
|
||||||
|
background-color: $grey;
|
||||||
|
height: 20em;
|
||||||
|
}
|
38
src/modules/logic-gates/components/LogicGatesPage.tsx
Normal file
38
src/modules/logic-gates/components/LogicGatesPage.tsx
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
import './LogicGatesPage.scss'
|
||||||
|
import React from 'react'
|
||||||
|
import { useObservable } from 'rxjs-hooks'
|
||||||
|
import { LogicGateList } from '../subjects/LogicGateList'
|
||||||
|
import { getTemplateSafely } from '../helpers/getTemplateSafely'
|
||||||
|
import { getRendererSafely } from '../helpers/getRendererSafely'
|
||||||
|
import LogicGate from './LogicGate'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The component containing the info / actions about all logic gates
|
||||||
|
*/
|
||||||
|
const LogicGatePage = () => {
|
||||||
|
const gates = useObservable(() => LogicGateList, [])
|
||||||
|
const renderer = getRendererSafely()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main>
|
||||||
|
<div className="page" id="gates-page">
|
||||||
|
<div className="gate-grid">
|
||||||
|
{gates
|
||||||
|
.map(getTemplateSafely)
|
||||||
|
.filter(template => {
|
||||||
|
return (
|
||||||
|
renderer.simulation.mode === 'project' ||
|
||||||
|
template.metadata.name !==
|
||||||
|
renderer.simulation.name
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.map((template, index) => {
|
||||||
|
return <LogicGate key={index} template={template} />
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LogicGatePage
|
12
src/modules/logic-gates/helpers/addGateFromTemplate.ts
Normal file
12
src/modules/logic-gates/helpers/addGateFromTemplate.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { GateTemplate } from '../../simulation/types/GateTemplate'
|
||||||
|
import { addGate } from '../../simulation/helpers/addGate'
|
||||||
|
import { getRendererSafely } from './getRendererSafely'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a gate to the current simulation from its template
|
||||||
|
*
|
||||||
|
* @param template The template to create
|
||||||
|
*/
|
||||||
|
export const addGateFromTemplate = (template: GateTemplate) => {
|
||||||
|
addGate(getRendererSafely(), template.metadata.name)
|
||||||
|
}
|
|
@ -1,11 +1,6 @@
|
||||||
import { InputStore } from '../../input/stores/InputStore'
|
import { InputStore } from '../../input/stores/InputStore'
|
||||||
import { open as logicGateModalIsOpen } from '../../logic-gates/components/LogicGateModal'
|
|
||||||
import { CreateSimulationStore } from '../../create-simulation/stores/CreateSimulationStore'
|
import { CreateSimulationStore } from '../../create-simulation/stores/CreateSimulationStore'
|
||||||
|
|
||||||
export const modalIsOpen = () => {
|
export const modalIsOpen = () => {
|
||||||
return (
|
return InputStore.data.open.value || CreateSimulationStore.data.open.value
|
||||||
InputStore.data.open.value ||
|
|
||||||
logicGateModalIsOpen.value ||
|
|
||||||
CreateSimulationStore.data.open.value
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,13 @@ import { SimulationRenderer } from '../../simulationRenderer/classes/SimulationR
|
||||||
import { DefaultGateTemplate } from '../constants'
|
import { DefaultGateTemplate } from '../constants'
|
||||||
import { vector2 } from '../../../common/math/classes/Transform'
|
import { vector2 } from '../../../common/math/classes/Transform'
|
||||||
import { Screen } from '../../screen/helpers/Screen'
|
import { Screen } from '../../screen/helpers/Screen'
|
||||||
|
import { toast } from 'react-toastify'
|
||||||
|
import { createToastArguments } from '../../toasts/helpers/createToastArguments'
|
||||||
|
import { CurrentLanguage } from '../../internalisation/stores/currentLanguage'
|
||||||
|
|
||||||
export const addGate = (renderer: SimulationRenderer, templateName: string) => {
|
export const addGate = (renderer: SimulationRenderer, templateName: string) => {
|
||||||
const template = templateStore.get(templateName)
|
const template = templateStore.get(templateName)
|
||||||
|
const translation = CurrentLanguage.getTranslation()
|
||||||
|
|
||||||
if (!template)
|
if (!template)
|
||||||
throw new SimulationError(`Cannot find template ${templateName}`)
|
throw new SimulationError(`Cannot find template ${templateName}`)
|
||||||
|
@ -32,4 +36,11 @@ export const addGate = (renderer: SimulationRenderer, templateName: string) => {
|
||||||
|
|
||||||
renderer.simulation.push(gate)
|
renderer.simulation.push(gate)
|
||||||
renderer.spawnCount++
|
renderer.spawnCount++
|
||||||
|
|
||||||
|
toast(
|
||||||
|
...createToastArguments(
|
||||||
|
translation.messages.addedGate(templateName),
|
||||||
|
'add_circle_outline'
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,6 @@ export class SimulationRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
public ref: RefObject<HTMLCanvasElement>,
|
|
||||||
options: Partial<SimulationRendererOptions> = {},
|
options: Partial<SimulationRendererOptions> = {},
|
||||||
public simulation = new Simulation('project', 'default')
|
public simulation = new Simulation('project', 'default')
|
||||||
) {
|
) {
|
||||||
|
@ -83,6 +82,8 @@ export class SimulationRenderer {
|
||||||
|
|
||||||
this.lastMousePosition = worldPosition
|
this.lastMousePosition = worldPosition
|
||||||
|
|
||||||
|
console.log('click')
|
||||||
|
|
||||||
// We need to iterate from the last to the first
|
// We need to iterate from the last to the first
|
||||||
// because if we have 2 overlapping gates,
|
// because if we have 2 overlapping gates,
|
||||||
// we want to select the one on top
|
// we want to select the one on top
|
||||||
|
@ -290,9 +291,9 @@ export class SimulationRenderer {
|
||||||
this.reloadSave()
|
this.reloadSave()
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateWheelListener() {
|
public updateWheelListener(ref: RefObject<HTMLCanvasElement>) {
|
||||||
if (this.ref.current) {
|
if (ref.current) {
|
||||||
this.ref.current.addEventListener('wheel', event => {
|
ref.current.addEventListener('wheel', event => {
|
||||||
if (!modalIsOpen()) {
|
if (!modalIsOpen()) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
||||||
|
|
16
src/modules/simulationRenderer/helpers/initRenderer.ts
Normal file
16
src/modules/simulationRenderer/helpers/initRenderer.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { rendererSubject } from '../../core/subjects/rendererSubject'
|
||||||
|
import { SimulationError } from '../../errors/classes/SimulationError'
|
||||||
|
import { SimulationRenderer } from '../classes/SimulationRenderer'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to create the simulationRenderer
|
||||||
|
*
|
||||||
|
* @throws SimulationError if the renderer already exists
|
||||||
|
*/
|
||||||
|
export const initRenderer = () => {
|
||||||
|
if (rendererSubject.value) {
|
||||||
|
throw new SimulationError('Renderer already inited')
|
||||||
|
} else {
|
||||||
|
rendererSubject.next(new SimulationRenderer())
|
||||||
|
}
|
||||||
|
}
|
4
src/public/robots.txt
Normal file
4
src/public/robots.txt
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
User-agent: *
|
||||||
|
Disallow: /server.js
|
||||||
|
Disallow: /js
|
||||||
|
Disallow: /css
|
|
@ -5,7 +5,7 @@ const app = express()
|
||||||
|
|
||||||
app.use(_static(__dirname))
|
app.use(_static(__dirname))
|
||||||
|
|
||||||
app.get('/', (rex, res) => {
|
app.get('*', (rex, res) => {
|
||||||
res.sendFile(resolve(__dirname, 'index.html'))
|
res.sendFile(resolve(__dirname, 'index.html'))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
||||||
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
|
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
|
||||||
const webpackMerge = require('webpack-merge')
|
const webpackMerge = require('webpack-merge')
|
||||||
const nodeExternals = require('webpack-node-externals')
|
const nodeExternals = require('webpack-node-externals')
|
||||||
|
const CopyPlugin = require('copy-webpack-plugin')
|
||||||
|
|
||||||
const isProduction = process.env.NODE_ENV === 'production'
|
const isProduction = process.env.NODE_ENV === 'production'
|
||||||
|
|
||||||
|
@ -71,7 +72,15 @@ const serverConfig = {
|
||||||
},
|
},
|
||||||
node: {
|
node: {
|
||||||
__dirname: false
|
__dirname: false
|
||||||
}
|
},
|
||||||
|
plugins: [
|
||||||
|
new CopyPlugin([
|
||||||
|
{
|
||||||
|
from: resolve(sourceFolder, 'public'),
|
||||||
|
to: buildFolder
|
||||||
|
}
|
||||||
|
])
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
const baseConfig = {
|
const baseConfig = {
|
||||||
|
|
Loading…
Reference in a new issue