internalisation
This commit is contained in:
parent
097c44e86e
commit
0c76f3cdf6
BIN
docs/assets/files.png
Normal file
BIN
docs/assets/files.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 105 KiB |
|
@ -6,6 +6,8 @@ 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'
|
||||||
|
|
||||||
|
console.clear()
|
||||||
|
|
||||||
handleErrors()
|
handleErrors()
|
||||||
initKeyBindings()
|
initKeyBindings()
|
||||||
initBaseTemplates()
|
initBaseTemplates()
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
import React, { Component, createRef, Ref, RefObject } from 'react'
|
import React, { Component, createRef, Ref, RefObject } from 'react'
|
||||||
import FluidCanvas from './FluidCanvas'
|
import FluidCanvas from './FluidCanvas'
|
||||||
import loop from 'mainloop.js'
|
import loop from 'mainloop.js'
|
||||||
import { Gate } from '../../simulation/classes/Gate'
|
|
||||||
import { SimulationRenderer } from '../../simulationRenderer/classes/SimulationRenderer'
|
import { SimulationRenderer } from '../../simulationRenderer/classes/SimulationRenderer'
|
||||||
import { renderSimulation } from '../../simulationRenderer/helpers/renderSimulation'
|
import { renderSimulation } from '../../simulationRenderer/helpers/renderSimulation'
|
||||||
import { updateSimulation } from '../../simulationRenderer/helpers/updateSimulation'
|
import { updateSimulation } from '../../simulationRenderer/helpers/updateSimulation'
|
||||||
import { addGate } from '../../simulation/helpers/addGate'
|
|
||||||
import { rendererSubject } from '../subjects/rendererSubject'
|
import { rendererSubject } from '../subjects/rendererSubject'
|
||||||
|
|
||||||
class Canvas extends Component {
|
class Canvas extends Component {
|
||||||
|
@ -18,8 +16,6 @@ class Canvas extends Component {
|
||||||
|
|
||||||
rendererSubject.next(this.renderer)
|
rendererSubject.next(this.renderer)
|
||||||
|
|
||||||
addGate(this.renderer.simulation, 'not')
|
|
||||||
|
|
||||||
loop.setDraw(() => {
|
loop.setDraw(() => {
|
||||||
if (this.renderingContext) {
|
if (this.renderingContext) {
|
||||||
renderSimulation(this.renderingContext, this.renderer)
|
renderSimulation(this.renderingContext, this.renderer)
|
||||||
|
|
28
src/modules/core/components/CreateSimulationButton.tsx
Normal file
28
src/modules/core/components/CreateSimulationButton.tsx
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
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 { handleCreating } from '../../create-simulation/helpers/handleCreating'
|
||||||
|
import { useTranslation } from '../../internalisation/helpers/useLanguage'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The component for the 'Create simulation' button from the top of the sidebar.
|
||||||
|
*
|
||||||
|
* The only way i found to apply a different color to the ListItem button was
|
||||||
|
* by using !important in the scss.
|
||||||
|
*/
|
||||||
|
const CreateSimulationButton = () => {
|
||||||
|
const translation = useTranslation()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ListItem button className="contained" onClick={handleCreating}>
|
||||||
|
<ListItemIcon>
|
||||||
|
<Icon>note_add</Icon>
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText>{translation.sidebar.createSimulation}</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CreateSimulationButton
|
93
src/modules/core/components/LogicGates.tsx
Normal file
93
src/modules/core/components/LogicGates.tsx
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
import React, { useState } from 'react'
|
||||||
|
import ListItem from '@material-ui/core/ListItem'
|
||||||
|
import ListItemIcon from '@material-ui/core/ListItemIcon'
|
||||||
|
import ListItemText from '@material-ui/core/ListItemText'
|
||||||
|
import Menu from '@material-ui/core/Menu'
|
||||||
|
import MenuItem from '@material-ui/core/MenuItem'
|
||||||
|
import Icon from '@material-ui/core/Icon'
|
||||||
|
import Typography from '@material-ui/core/Typography'
|
||||||
|
import { BehaviorSubject } from 'rxjs'
|
||||||
|
import { useObservable } from 'rxjs-hooks'
|
||||||
|
import { switchTo } from '../../saving/helpers/switchTo'
|
||||||
|
import { SimulationError } from '../../errors/classes/SimulationError'
|
||||||
|
import { templateStore } from '../../saving/stores/templateStore'
|
||||||
|
import { useTranslation } from '../../internalisation/helpers/useLanguage'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subject to make React update the dom when new gates are stored
|
||||||
|
*/
|
||||||
|
const allGatesSubject = new BehaviorSubject<string[]>([])
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers a dom update by pushing a new value to the
|
||||||
|
* useObservable hook inside the React component.
|
||||||
|
*
|
||||||
|
* It also has the side effect of sorting the template names.
|
||||||
|
*/
|
||||||
|
const updateTemplateList = () => {
|
||||||
|
allGatesSubject.next(templateStore.ls().sort())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component wich contains the sidebar 'Open simulation' button
|
||||||
|
*
|
||||||
|
* @throws SimulationError if the data about a simulation cant be found in localStorage
|
||||||
|
*/
|
||||||
|
const LogicGates = () => {
|
||||||
|
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null)
|
||||||
|
const simulations = useObservable(() => allGatesSubject, [])
|
||||||
|
|
||||||
|
const translation = useTranslation()
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
setAnchorEl(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ListItem
|
||||||
|
button
|
||||||
|
onClick={event => {
|
||||||
|
updateTemplateList()
|
||||||
|
setAnchorEl(event.currentTarget)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ListItemIcon>
|
||||||
|
<Icon>memory</Icon>
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText>{translation.sidebar.logicGates}</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
|
||||||
|
<Menu
|
||||||
|
keepMounted
|
||||||
|
anchorEl={anchorEl}
|
||||||
|
open={Boolean(anchorEl)}
|
||||||
|
onClose={handleClose}
|
||||||
|
>
|
||||||
|
{simulations.map((simulationName, index) => {
|
||||||
|
const simulationData = templateStore.get(simulationName)
|
||||||
|
|
||||||
|
if (!simulationData) {
|
||||||
|
throw new SimulationError(
|
||||||
|
`Cannot get data for simulation ${simulationName}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MenuItem
|
||||||
|
key={index}
|
||||||
|
onClick={() => {
|
||||||
|
switchTo(simulationName)
|
||||||
|
handleClose()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography>{simulationName}</Typography>
|
||||||
|
</MenuItem>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</Menu>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LogicGates
|
|
@ -5,24 +5,48 @@ import ListItemText from '@material-ui/core/ListItemText'
|
||||||
import Menu from '@material-ui/core/Menu'
|
import Menu from '@material-ui/core/Menu'
|
||||||
import MenuItem from '@material-ui/core/MenuItem'
|
import MenuItem from '@material-ui/core/MenuItem'
|
||||||
import Icon from '@material-ui/core/Icon'
|
import Icon from '@material-ui/core/Icon'
|
||||||
|
import Typography from '@material-ui/core/Typography'
|
||||||
import { saveStore } from '../../saving/stores/saveStore'
|
import { saveStore } from '../../saving/stores/saveStore'
|
||||||
import { BehaviorSubject } from 'rxjs'
|
import { BehaviorSubject } from 'rxjs'
|
||||||
import { useObservable } from 'rxjs-hooks'
|
import { useObservable } from 'rxjs-hooks'
|
||||||
import { rendererSubject } from '../subjects/rendererSubject'
|
import { switchTo } from '../../saving/helpers/switchTo'
|
||||||
import { currentStore } from '../../saving/stores/currentStore'
|
import { SimulationError } from '../../errors/classes/SimulationError'
|
||||||
|
import { icons } from '../constants'
|
||||||
|
import { useTranslation } from '../../internalisation/helpers/useLanguage'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list with the names of all saved simulations
|
||||||
|
*/
|
||||||
const allSimulations = () => {
|
const allSimulations = () => {
|
||||||
return saveStore.ls()
|
return saveStore.ls()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subject to make React update the dom when new simulations are stored
|
||||||
|
*/
|
||||||
const allSimulationSubject = new BehaviorSubject<string[]>([])
|
const allSimulationSubject = new BehaviorSubject<string[]>([])
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers a dom update by pushing a new value to the
|
||||||
|
* useObservable hook inside the React component.
|
||||||
|
*
|
||||||
|
* It also has the side effect of sorting the simulation names.
|
||||||
|
*/
|
||||||
const updateSimulationList = () => {
|
const updateSimulationList = () => {
|
||||||
allSimulationSubject.next(allSimulations())
|
allSimulationSubject.next(allSimulations().sort())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component wich contains the sidebar 'Open simulation' button
|
||||||
|
*
|
||||||
|
* @throws SimulationError if the data about a simulation cant be found in localStorage
|
||||||
|
*/
|
||||||
const OpenSimulation = () => {
|
const OpenSimulation = () => {
|
||||||
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null)
|
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null)
|
||||||
const simulations = useObservable(() => allSimulationSubject, [])
|
const simulations = useObservable(() => allSimulationSubject, [])
|
||||||
|
|
||||||
|
const translation = useTranslation()
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setAnchorEl(null)
|
setAnchorEl(null)
|
||||||
}
|
}
|
||||||
|
@ -39,7 +63,9 @@ const OpenSimulation = () => {
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<Icon>folder_open</Icon>
|
<Icon>folder_open</Icon>
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText>Open simulation</ListItemText>
|
<ListItemText>
|
||||||
|
{translation.sidebar.openSimulation}
|
||||||
|
</ListItemText>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
|
|
||||||
<Menu
|
<Menu
|
||||||
|
@ -48,23 +74,36 @@ const OpenSimulation = () => {
|
||||||
open={Boolean(anchorEl)}
|
open={Boolean(anchorEl)}
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
>
|
>
|
||||||
{simulations.map((simulation, index) => (
|
{simulations.map((simulationName, index) => {
|
||||||
|
const simulationData = saveStore.get(simulationName)
|
||||||
|
|
||||||
|
if (!simulationData) {
|
||||||
|
throw new SimulationError(
|
||||||
|
`Cannot get data for simulation ${simulationName}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
key={index}
|
key={index}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (rendererSubject.value) {
|
switchTo(simulationName)
|
||||||
const renderer = rendererSubject.value
|
|
||||||
|
|
||||||
currentStore.set(simulation)
|
|
||||||
renderer.reloadSave()
|
|
||||||
}
|
|
||||||
|
|
||||||
handleClose()
|
handleClose()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{simulation}
|
<ListItemIcon>
|
||||||
|
<Icon>
|
||||||
|
{
|
||||||
|
icons.simulationMode[
|
||||||
|
simulationData.simulation.mode
|
||||||
|
]
|
||||||
|
}
|
||||||
|
</Icon>
|
||||||
|
</ListItemIcon>
|
||||||
|
<Typography>{simulationName}</Typography>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
)
|
||||||
|
})}
|
||||||
</Menu>
|
</Menu>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,35 +1,51 @@
|
||||||
import React, { useState } from 'react'
|
import React from 'react'
|
||||||
import Drawer from '@material-ui/core/Drawer'
|
import Drawer from '@material-ui/core/Drawer'
|
||||||
import List from '@material-ui/core/List'
|
import List from '@material-ui/core/List'
|
||||||
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 { handleCreating } from '../../create-simulation/helpers/handleCreating'
|
|
||||||
import { makeStyles, Theme, createStyles } from '@material-ui/core/styles'
|
|
||||||
import OpenSimulation from './OpenSimulation'
|
import OpenSimulation from './OpenSimulation'
|
||||||
|
import CreateSimulationButton from './CreateSimulationButton'
|
||||||
|
import LogicGates from './LogicGates'
|
||||||
|
import { makeStyles, createStyles } from '@material-ui/core/styles'
|
||||||
|
/**
|
||||||
|
* The width of the sidebar
|
||||||
|
*/
|
||||||
|
const sidebarWidth = 240
|
||||||
|
|
||||||
const drawerWidth = 240
|
/**
|
||||||
const useStyles = makeStyles((theme: Theme) =>
|
* The z-index of the sidebar.
|
||||||
|
*/
|
||||||
|
const sidebarZIndex = 5
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The styles for the sidebar component
|
||||||
|
*/
|
||||||
|
const useStyles = makeStyles(
|
||||||
createStyles({
|
createStyles({
|
||||||
|
// This class is applied on the sidebar container
|
||||||
root: {
|
root: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
zIndex: 5
|
zIndex: sidebarZIndex
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// This is the class of the actual sidebar
|
||||||
drawer: {
|
drawer: {
|
||||||
width: drawerWidth,
|
width: sidebarWidth,
|
||||||
flexShrink: 0,
|
zIndex: sidebarZIndex,
|
||||||
zIndex: 5
|
flexShrink: 0
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// This is the class for the surface of the sidebar
|
||||||
drawerPaper: {
|
drawerPaper: {
|
||||||
padding: '4px',
|
|
||||||
width: drawerWidth,
|
|
||||||
background: `#111111`,
|
background: `#111111`,
|
||||||
zIndex: 5
|
padding: '4px',
|
||||||
|
width: sidebarWidth,
|
||||||
|
zIndex: sidebarZIndex
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sidebar component
|
||||||
|
*/
|
||||||
const Sidebar = () => {
|
const Sidebar = () => {
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
|
|
||||||
|
@ -44,18 +60,10 @@ const Sidebar = () => {
|
||||||
paper: classes.drawerPaper
|
paper: classes.drawerPaper
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<List component="nav" aria-label="Main mailbox folders">
|
<List component="nav">
|
||||||
<ListItem
|
<CreateSimulationButton />
|
||||||
button
|
|
||||||
className="contained"
|
|
||||||
onClick={handleCreating}
|
|
||||||
>
|
|
||||||
<ListItemIcon>
|
|
||||||
<Icon>note_add</Icon>
|
|
||||||
</ListItemIcon>
|
|
||||||
<ListItemText>Create simulation</ListItemText>
|
|
||||||
</ListItem>
|
|
||||||
<OpenSimulation />
|
<OpenSimulation />
|
||||||
|
<LogicGates />
|
||||||
</List>
|
</List>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { createMuiTheme } from '@material-ui/core/styles'
|
import { createMuiTheme } from '@material-ui/core/styles'
|
||||||
import { red, deepPurple } from '@material-ui/core/colors'
|
import { red, deepPurple } from '@material-ui/core/colors'
|
||||||
|
import { simulationMode } from '../saving/types/SimulationSave'
|
||||||
|
|
||||||
export const theme = createMuiTheme({
|
export const theme = createMuiTheme({
|
||||||
palette: {
|
palette: {
|
||||||
|
@ -8,3 +9,20 @@ export const theme = createMuiTheme({
|
||||||
secondary: red
|
secondary: red
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to get intellisense from visual studio code
|
||||||
|
*/
|
||||||
|
export interface IconInterface {
|
||||||
|
simulationMode: Record<simulationMode, string>
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the names of icons reuseed truogh the app
|
||||||
|
*/
|
||||||
|
export const icons: IconInterface = {
|
||||||
|
simulationMode: {
|
||||||
|
project: 'gamepad',
|
||||||
|
ic: 'memory'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,21 +4,19 @@ import { useObservable } from 'rxjs-hooks'
|
||||||
import { CreateSimulationStore } from '../stores/CreateSimulationStore'
|
import { CreateSimulationStore } from '../stores/CreateSimulationStore'
|
||||||
import { simulationMode } from '../../saving/types/SimulationSave'
|
import { simulationMode } from '../../saving/types/SimulationSave'
|
||||||
import Icon from '@material-ui/core/Icon'
|
import Icon from '@material-ui/core/Icon'
|
||||||
|
import { useTranslation } from '../../internalisation/helpers/useLanguage'
|
||||||
|
|
||||||
export interface CreateSimulationOption {
|
export interface CreateSimulationOption {
|
||||||
mode: simulationMode
|
mode: simulationMode
|
||||||
icon: string
|
icon: string
|
||||||
name: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createSimulationOptions: CreateSimulationOption[] = [
|
export const createSimulationOptions: CreateSimulationOption[] = [
|
||||||
{
|
{
|
||||||
name: 'project',
|
|
||||||
mode: 'project',
|
mode: 'project',
|
||||||
icon: 'gamepad'
|
icon: 'gamepad'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'integrated circuit',
|
|
||||||
icon: 'memory',
|
icon: 'memory',
|
||||||
mode: 'ic'
|
mode: 'ic'
|
||||||
}
|
}
|
||||||
|
@ -26,6 +24,7 @@ export const createSimulationOptions: CreateSimulationOption[] = [
|
||||||
|
|
||||||
const CreateSimulation = () => {
|
const CreateSimulation = () => {
|
||||||
const open = useObservable(() => CreateSimulationStore.data.open, false)
|
const open = useObservable(() => CreateSimulationStore.data.open, false)
|
||||||
|
const translation = useTranslation()
|
||||||
|
|
||||||
const closeModal = () => {
|
const closeModal = () => {
|
||||||
CreateSimulationStore.actions.next('quit')
|
CreateSimulationStore.actions.next('quit')
|
||||||
|
@ -38,7 +37,7 @@ const CreateSimulation = () => {
|
||||||
onClick={closeModal}
|
onClick={closeModal}
|
||||||
>
|
>
|
||||||
<div id="create-title">
|
<div id="create-title">
|
||||||
What kind of simulation do you want to create?
|
{translation.createSimulation.mode.question}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="create-options">
|
<div id="create-options">
|
||||||
|
@ -57,7 +56,11 @@ const CreateSimulation = () => {
|
||||||
<Icon>{option.icon}</Icon>
|
<Icon>{option.icon}</Icon>
|
||||||
</div>
|
</div>
|
||||||
<div className="create-option-name" id={option.mode}>
|
<div className="create-option-name" id={option.mode}>
|
||||||
{option.name}
|
{
|
||||||
|
translation.createSimulation.mode.options[
|
||||||
|
option.mode
|
||||||
|
]
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { CreateSimulationStore } from '../stores/CreateSimulationStore'
|
import { CreateSimulationStore } from '../stores/CreateSimulationStore'
|
||||||
import { initSimulation } from '../../saving/helpers/initSimulation'
|
import { initSimulation } from '../../saving/helpers/initSimulation'
|
||||||
|
import { switchTo } from '../../saving/helpers/switchTo'
|
||||||
|
|
||||||
export const handleCreating = async () => {
|
export const handleCreating = async () => {
|
||||||
const options = await CreateSimulationStore.create()
|
const options = await CreateSimulationStore.create()
|
||||||
|
@ -8,5 +9,7 @@ export const handleCreating = async () => {
|
||||||
|
|
||||||
const simulation = initSimulation(options.name, options.mode)
|
const simulation = initSimulation(options.name, options.mode)
|
||||||
|
|
||||||
|
switchTo(options.name)
|
||||||
|
|
||||||
return simulation
|
return simulation
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { BehaviorSubject, Subject } from 'rxjs'
|
||||||
import { take } from 'rxjs/operators'
|
import { take } from 'rxjs/operators'
|
||||||
import { simulationMode } from '../../saving/types/SimulationSave'
|
import { simulationMode } from '../../saving/types/SimulationSave'
|
||||||
import { InputStore } from '../../input/stores/InputStore'
|
import { InputStore } from '../../input/stores/InputStore'
|
||||||
|
import { CurrentLanguage } from '../../internalisation/stores/currentLanguage'
|
||||||
|
|
||||||
export type CreateSimulationStoreAction = 'quit' | 'submit'
|
export type CreateSimulationStoreAction = 'quit' | 'submit'
|
||||||
|
|
||||||
|
@ -13,6 +14,8 @@ export const CreateSimulationStore = {
|
||||||
.pipe(take(1))
|
.pipe(take(1))
|
||||||
.toPromise()
|
.toPromise()
|
||||||
|
|
||||||
|
const translation = CurrentLanguage.getTranslation()
|
||||||
|
|
||||||
CreateSimulationStore.close()
|
CreateSimulationStore.close()
|
||||||
|
|
||||||
if (action === 'quit') {
|
if (action === 'quit') {
|
||||||
|
@ -20,7 +23,7 @@ export const CreateSimulationStore = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const name = await InputStore.get(
|
const name = await InputStore.get(
|
||||||
'What do you want your simulation to be called?'
|
translation.createSimulation.name.question
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!name) {
|
if (!name) {
|
||||||
|
|
12
src/modules/internalisation/constants.ts
Normal file
12
src/modules/internalisation/constants.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { supportedLanguages } from './types/supportedLanguages'
|
||||||
|
import { Translation } from './types/TranslationInterface'
|
||||||
|
import { EnglishTranslation } from './translations/english'
|
||||||
|
import { RomanianTranslation } from './translations/romanian'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Object with all translations
|
||||||
|
*/
|
||||||
|
export const translations: Record<supportedLanguages, Translation> = {
|
||||||
|
english: EnglishTranslation,
|
||||||
|
['română']: RomanianTranslation
|
||||||
|
}
|
16
src/modules/internalisation/helpers/useLanguage.ts
Normal file
16
src/modules/internalisation/helpers/useLanguage.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { useObservable } from 'rxjs-hooks'
|
||||||
|
import currentLanguageSubject from '../subjects/currentLanguageSubject'
|
||||||
|
import { translations } from '../constants'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook to get the current translation
|
||||||
|
*/
|
||||||
|
export const useTranslation = () => {
|
||||||
|
const currentLanguage = useObservable(
|
||||||
|
() => currentLanguageSubject,
|
||||||
|
'english'
|
||||||
|
)
|
||||||
|
const translation = translations[currentLanguage]
|
||||||
|
|
||||||
|
return translation
|
||||||
|
}
|
53
src/modules/internalisation/stores/currentLanguage.ts
Normal file
53
src/modules/internalisation/stores/currentLanguage.ts
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
import { supportedLanguages } from '../types/supportedLanguages'
|
||||||
|
import { LocalStore } from '../../storage/classes/LocalStore'
|
||||||
|
import currentLanguageSubject from './../subjects/currentLanguageSubject'
|
||||||
|
import { SimulationError } from '../../errors/classes/SimulationError'
|
||||||
|
import { translations } from '../constants'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local store containing the current selected language
|
||||||
|
*/
|
||||||
|
export const CurrentLanguageLocalStore = new LocalStore<supportedLanguages>(
|
||||||
|
'language'
|
||||||
|
)
|
||||||
|
|
||||||
|
// This makes sure the language isnt undefined
|
||||||
|
if (!CurrentLanguageLocalStore.get()) {
|
||||||
|
CurrentLanguageLocalStore.set('english')
|
||||||
|
}
|
||||||
|
|
||||||
|
currentLanguageSubject.next(CurrentLanguageLocalStore.get() || 'english')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The preffered interface for interacting with CurrentLanguageLocalStore
|
||||||
|
*/
|
||||||
|
const CurrentLanguage = {
|
||||||
|
set(name: supportedLanguages) {
|
||||||
|
CurrentLanguageLocalStore.set(name)
|
||||||
|
currentLanguageSubject.next(name)
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to get the current selected store
|
||||||
|
*
|
||||||
|
* @throws SimulationError if the language cannot be found
|
||||||
|
*/
|
||||||
|
get() {
|
||||||
|
const language = CurrentLanguageLocalStore.get()
|
||||||
|
|
||||||
|
if (!language) {
|
||||||
|
throw new SimulationError(`Current language not found`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return language
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to get the current translation outside React components
|
||||||
|
*/
|
||||||
|
getTranslation() {
|
||||||
|
return translations[CurrentLanguage.get()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { CurrentLanguage }
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { BehaviorSubject } from 'rxjs'
|
||||||
|
import { supportedLanguages } from '../types/supportedLanguages'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subject with the current language
|
||||||
|
*/
|
||||||
|
export default new BehaviorSubject<supportedLanguages>('english')
|
31
src/modules/internalisation/translations/english.ts
Normal file
31
src/modules/internalisation/translations/english.ts
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import { Translation } from '../types/TranslationInterface'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The enaglish translation
|
||||||
|
*/
|
||||||
|
export const EnglishTranslation: Translation = {
|
||||||
|
language: 'english',
|
||||||
|
sidebar: {
|
||||||
|
createSimulation: 'Create simulation',
|
||||||
|
logicGates: 'Logic gates',
|
||||||
|
openSimulation: 'Open simulations'
|
||||||
|
},
|
||||||
|
createSimulation: {
|
||||||
|
mode: {
|
||||||
|
question: 'What kind of simulation do you want to create?',
|
||||||
|
options: {
|
||||||
|
ic: 'Integrated circuit',
|
||||||
|
project: 'Project'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
question: 'What do you want your simulation to be called?'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
messages: {
|
||||||
|
createdSimulation: name => `Succesfully created simulation '${name}'`,
|
||||||
|
switchedToSimulation: name =>
|
||||||
|
`Succesfully switched to simulation '${name}'`,
|
||||||
|
savedSimulation: name => `Succesfully saved simulation '${name}'`
|
||||||
|
}
|
||||||
|
}
|
32
src/modules/internalisation/translations/romanian.ts
Normal file
32
src/modules/internalisation/translations/romanian.ts
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import { Translation } from '../types/TranslationInterface'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The romanian translation
|
||||||
|
*/
|
||||||
|
export const RomanianTranslation: Translation = {
|
||||||
|
language: 'română',
|
||||||
|
sidebar: {
|
||||||
|
createSimulation: 'Creează o simulație',
|
||||||
|
openSimulation: 'Deschide o simulație',
|
||||||
|
logicGates: 'Porți logice'
|
||||||
|
},
|
||||||
|
createSimulation: {
|
||||||
|
mode: {
|
||||||
|
question: 'Ce fel de simulație vrei să creiezi?',
|
||||||
|
options: {
|
||||||
|
ic: 'Circuit integrat',
|
||||||
|
project: 'Proiect'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
question: 'Cum vrei să numești simulația?'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
messages: {
|
||||||
|
createdSimulation: name =>
|
||||||
|
`Simulația '${name}' a fost creiată cu succes`,
|
||||||
|
switchedToSimulation: name =>
|
||||||
|
`Simulația '${name}' a fost deschisă cu succes`,
|
||||||
|
savedSimulation: name => `Simulația '${name}' a fost salvată cu succes`
|
||||||
|
}
|
||||||
|
}
|
31
src/modules/internalisation/types/TranslationInterface.ts
Normal file
31
src/modules/internalisation/types/TranslationInterface.ts
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import { supportedLanguages } from './supportedLanguages'
|
||||||
|
import { simulationMode } from '../../saving/types/SimulationSave'
|
||||||
|
|
||||||
|
export type SentenceFactory<T extends string[]> = (...names: T) => string
|
||||||
|
export type NameSentence = SentenceFactory<[string]>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interface all translations need to follow
|
||||||
|
*/
|
||||||
|
export interface Translation {
|
||||||
|
language: supportedLanguages
|
||||||
|
sidebar: {
|
||||||
|
createSimulation: string
|
||||||
|
openSimulation: string
|
||||||
|
logicGates: string
|
||||||
|
}
|
||||||
|
createSimulation: {
|
||||||
|
mode: {
|
||||||
|
question: string
|
||||||
|
options: Record<simulationMode, string>
|
||||||
|
}
|
||||||
|
name: {
|
||||||
|
question: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
messages: {
|
||||||
|
createdSimulation: NameSentence
|
||||||
|
switchedToSimulation: NameSentence
|
||||||
|
savedSimulation: NameSentence
|
||||||
|
}
|
||||||
|
}
|
4
src/modules/internalisation/types/supportedLanguages.ts
Normal file
4
src/modules/internalisation/types/supportedLanguages.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
/**
|
||||||
|
* Type containing the names of all supported languages
|
||||||
|
*/
|
||||||
|
export type supportedLanguages = 'română' | 'english'
|
|
@ -13,5 +13,5 @@
|
||||||
z-index: $modal-index;
|
z-index: $modal-index;
|
||||||
color: white;
|
color: white;
|
||||||
background-color: $modal-bg-color;
|
background-color: $modal-bg-color;
|
||||||
font-family: 'Righteous';
|
font-family: 'Righteous', cursive;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1,6 @@
|
||||||
|
/**
|
||||||
|
* Very basic JSON based object cloning
|
||||||
|
*
|
||||||
|
* @param state The object to clone
|
||||||
|
*/
|
||||||
export const cloneState = <T>(state: T): T => JSON.parse(JSON.stringify(state))
|
export const cloneState = <T>(state: T): T => JSON.parse(JSON.stringify(state))
|
||||||
|
|
16
src/modules/saving/helpers/dumpSimulation.ts
Normal file
16
src/modules/saving/helpers/dumpSimulation.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { SimulationRenderer } from '../../simulationRenderer/classes/SimulationRenderer'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does the cleanup for switching to another simulation
|
||||||
|
*
|
||||||
|
* @param renderer The renderer to clean up
|
||||||
|
*/
|
||||||
|
export const dumpSimulation = (renderer: SimulationRenderer) => {
|
||||||
|
renderer.simulation.dispose()
|
||||||
|
renderer.lastMousePosition = [0, 0]
|
||||||
|
renderer.selectedGate = null
|
||||||
|
renderer.selectedPins = {
|
||||||
|
end: null,
|
||||||
|
start: null
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,6 @@
|
||||||
import { SimulationRenderer } from '../../simulationRenderer/classes/SimulationRenderer'
|
|
||||||
import { Gate, PinWrapper } from '../../simulation/classes/Gate'
|
import { Gate, PinWrapper } from '../../simulation/classes/Gate'
|
||||||
import {
|
import {
|
||||||
TransformState,
|
TransformState,
|
||||||
RendererState,
|
|
||||||
CameraState,
|
CameraState,
|
||||||
SimulationState
|
SimulationState
|
||||||
} from '../types/SimulationSave'
|
} from '../types/SimulationSave'
|
||||||
|
@ -12,6 +10,10 @@ import { Simulation } from '../../simulation/classes/Simulation'
|
||||||
import { Wire } from '../../simulation/classes/Wire'
|
import { Wire } from '../../simulation/classes/Wire'
|
||||||
import { templateStore } from '../stores/templateStore'
|
import { templateStore } from '../stores/templateStore'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains methods for transforming saved state into the respective class instances
|
||||||
|
*/
|
||||||
|
|
||||||
export const fromTransformState = (state: TransformState): Transform => {
|
export const fromTransformState = (state: TransformState): Transform => {
|
||||||
return new Transform(state.position, state.scale, state.rotation)
|
return new Transform(state.position, state.scale, state.rotation)
|
||||||
}
|
}
|
||||||
|
@ -25,7 +27,7 @@ export const fromCameraState = (state: CameraState): Camera => {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fromSimulationState = (state: SimulationState): Simulation => {
|
export const fromSimulationState = (state: SimulationState): Simulation => {
|
||||||
const simulation = new Simulation(state.mode)
|
const simulation = new Simulation(state.mode, state.name)
|
||||||
|
|
||||||
for (const gateState of state.gates) {
|
for (const gateState of state.gates) {
|
||||||
const gate = new Gate(
|
const gate = new Gate(
|
||||||
|
|
|
@ -14,6 +14,10 @@ import { Camera } from '../../simulationRenderer/classes/Camera'
|
||||||
import { Simulation } from '../../simulation/classes/Simulation'
|
import { Simulation } from '../../simulation/classes/Simulation'
|
||||||
import { Wire } from '../../simulation/classes/Wire'
|
import { Wire } from '../../simulation/classes/Wire'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Methods for gettings the savable state from class instances
|
||||||
|
*/
|
||||||
|
|
||||||
export const getTransformState = (transform: Transform): TransformState => {
|
export const getTransformState = (transform: Transform): TransformState => {
|
||||||
return {
|
return {
|
||||||
position: transform.position,
|
position: transform.position,
|
||||||
|
|
|
@ -1,10 +1,20 @@
|
||||||
import { baseTemplates } from '../constants'
|
import { baseTemplates } from '../constants'
|
||||||
import { templateStore } from '../stores/templateStore'
|
import { templateStore } from '../stores/templateStore'
|
||||||
|
import { SimulationError } from '../../errors/classes/SimulationError'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the base logic gate templates into localStorage
|
||||||
|
*
|
||||||
|
* @throws SimulationError if something is wrong with the template
|
||||||
|
*/
|
||||||
export const initBaseTemplates = () => {
|
export const initBaseTemplates = () => {
|
||||||
for (const template of baseTemplates) {
|
for (const template of baseTemplates) {
|
||||||
if (template.metadata && template.metadata.name) {
|
if (template.metadata && template.metadata.name) {
|
||||||
templateStore.set(template.metadata.name, template)
|
templateStore.set(template.metadata.name, template)
|
||||||
|
} else {
|
||||||
|
throw new SimulationError(
|
||||||
|
`Template ${JSON.stringify(template)} cannot be stored.`
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,20 @@ import { cloneState } from './cloneState'
|
||||||
import { saveStore } from '../stores/saveStore'
|
import { saveStore } from '../stores/saveStore'
|
||||||
import { toast } from 'react-toastify'
|
import { toast } from 'react-toastify'
|
||||||
import { createToastArguments } from '../../toasts/helpers/createToastArguments'
|
import { createToastArguments } from '../../toasts/helpers/createToastArguments'
|
||||||
|
import { CurrentLanguage } from '../../internalisation/stores/currentLanguage'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inits a simulation by:
|
||||||
|
* 1) first initialising the place in localstorage
|
||||||
|
* where the simulation will be saved
|
||||||
|
* 2) notifying the used about that
|
||||||
|
*
|
||||||
|
* @param name - the name of the simulation
|
||||||
|
* @param mode - the mode of the simulation
|
||||||
|
*/
|
||||||
export const initSimulation = (name: string, mode: simulationMode) => {
|
export const initSimulation = (name: string, mode: simulationMode) => {
|
||||||
const state = cloneState(baseSave)
|
const state = cloneState(baseSave)
|
||||||
|
const translation = CurrentLanguage.getTranslation()
|
||||||
|
|
||||||
state.simulation.name = name
|
state.simulation.name = name
|
||||||
state.simulation.mode = mode
|
state.simulation.mode = mode
|
||||||
|
@ -15,7 +26,7 @@ export const initSimulation = (name: string, mode: simulationMode) => {
|
||||||
|
|
||||||
toast.success(
|
toast.success(
|
||||||
...createToastArguments(
|
...createToastArguments(
|
||||||
`Successfully created simulation ${name}`,
|
translation.messages.createdSimulation(name),
|
||||||
'check'
|
'check'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,16 +5,32 @@ import { getRendererState } from './getState'
|
||||||
import { saveStore } from '../stores/saveStore'
|
import { saveStore } from '../stores/saveStore'
|
||||||
import { toast } from 'react-toastify'
|
import { toast } from 'react-toastify'
|
||||||
import { createToastArguments } from '../../toasts/helpers/createToastArguments'
|
import { createToastArguments } from '../../toasts/helpers/createToastArguments'
|
||||||
|
import { CurrentLanguage } from '../../internalisation/stores/currentLanguage'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the state from a renderer in localStorage,
|
||||||
|
* then notifies the user about it
|
||||||
|
*
|
||||||
|
* @throws SimulationError if the simulation name
|
||||||
|
* cannot found in the currentStore
|
||||||
|
*
|
||||||
|
* @param renderer - the renderer to saev the state of
|
||||||
|
*/
|
||||||
export const save = (renderer: SimulationRenderer) => {
|
export const save = (renderer: SimulationRenderer) => {
|
||||||
const current = currentStore.get()
|
const current = currentStore.get()
|
||||||
|
|
||||||
if (current) {
|
if (current) {
|
||||||
const state = getRendererState(renderer)
|
const state = getRendererState(renderer)
|
||||||
|
const translation = CurrentLanguage.getTranslation()
|
||||||
|
|
||||||
saveStore.set(current, state)
|
saveStore.set(current, state)
|
||||||
|
|
||||||
toast(...createToastArguments(`Succesfully saved ${current}`, 'save'))
|
toast(
|
||||||
|
...createToastArguments(
|
||||||
|
translation.messages.savedSimulation(current),
|
||||||
|
'save'
|
||||||
|
)
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
throw new SimulationError(
|
throw new SimulationError(
|
||||||
'Cannot save without knowing the name of the active simulation'
|
'Cannot save without knowing the name of the active simulation'
|
||||||
|
|
42
src/modules/saving/helpers/switchTo.ts
Normal file
42
src/modules/saving/helpers/switchTo.ts
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
import { currentStore } from '../stores/currentStore'
|
||||||
|
import { rendererSubject } from '../../core/subjects/rendererSubject'
|
||||||
|
import { SimulationError } from '../../errors/classes/SimulationError'
|
||||||
|
import { toast } from 'react-toastify'
|
||||||
|
import { createToastArguments } from '../../toasts/helpers/createToastArguments'
|
||||||
|
import { dumpSimulation } from './dumpSimulation'
|
||||||
|
import { CurrentLanguage } from '../../internalisation/stores/currentLanguage'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to switch to a simulation
|
||||||
|
*
|
||||||
|
* @throws SimulationError if theres no renderer stored in the rendererSubject
|
||||||
|
*
|
||||||
|
* @param simulationName The name of the simulation to switch to
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* switchTo()
|
||||||
|
* switchTo('test')
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export const switchTo = (simulationName: string = 'default') => {
|
||||||
|
if (rendererSubject.value) {
|
||||||
|
const renderer = rendererSubject.value
|
||||||
|
const translation = CurrentLanguage.getTranslation()
|
||||||
|
|
||||||
|
dumpSimulation(renderer)
|
||||||
|
|
||||||
|
currentStore.set(simulationName)
|
||||||
|
renderer.reloadSave()
|
||||||
|
|
||||||
|
toast(
|
||||||
|
...createToastArguments(
|
||||||
|
translation.messages.switchedToSimulation(simulationName),
|
||||||
|
'arrow_right_alt'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
throw new SimulationError(
|
||||||
|
`Renderer not found while trying to switch to simulation '${simulationName}'`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,12 @@
|
||||||
import { LocalStore } from '../../storage/classes/LocalStore'
|
import { LocalStore } from '../../storage/classes/LocalStore'
|
||||||
import { defaultSimulationName } from '../constants'
|
import { defaultSimulationName } from '../constants'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the name of the current simulation
|
||||||
|
*/
|
||||||
const currentStore = new LocalStore<string>('currentSave')
|
const currentStore = new LocalStore<string>('currentSave')
|
||||||
|
|
||||||
|
// This makes sure the store isnt empty
|
||||||
if (!currentStore.get()) {
|
if (!currentStore.get()) {
|
||||||
currentStore.set(defaultSimulationName)
|
currentStore.set(defaultSimulationName)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
import { LocalStore } from '../../storage/classes/LocalStore'
|
import { LocalStore } from '../../storage/classes/LocalStore'
|
||||||
import { RendererState } from '../types/SimulationSave'
|
import { RendererState } from '../types/SimulationSave'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This store is used to save all simulations.
|
||||||
|
*/
|
||||||
export const saveStore = new LocalStore<RendererState>('saves')
|
export const saveStore = new LocalStore<RendererState>('saves')
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import { LocalStore } from '../../storage/classes/LocalStore'
|
import { LocalStore } from '../../storage/classes/LocalStore'
|
||||||
import { GateTemplate } from '../../simulation/types/GateTemplate'
|
import { GateTemplate } from '../../simulation/types/GateTemplate'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This store is used to save all logic gate templates
|
||||||
|
*/
|
||||||
export const templateStore = new LocalStore<DeepPartial<GateTemplate>>(
|
export const templateStore = new LocalStore<DeepPartial<GateTemplate>>(
|
||||||
'templates'
|
'templates'
|
||||||
)
|
)
|
||||||
|
|
|
@ -27,6 +27,7 @@ import { wireConnectedToGate } from '../helpers/wireConnectedToGate'
|
||||||
import { updateMouse, handleScroll } from '../helpers/scaleCanvas'
|
import { updateMouse, handleScroll } from '../helpers/scaleCanvas'
|
||||||
import { RefObject } from 'react'
|
import { RefObject } from 'react'
|
||||||
import { Singleton } from '@eix-js/utils'
|
import { Singleton } from '@eix-js/utils'
|
||||||
|
import { dumpSimulation } from '../../saving/helpers/dumpSimulation'
|
||||||
|
|
||||||
export class SimulationRenderer {
|
export class SimulationRenderer {
|
||||||
public mouseDownOutput = new Subject<MouseEventInfo>()
|
public mouseDownOutput = new Subject<MouseEventInfo>()
|
||||||
|
@ -200,6 +201,8 @@ export class SimulationRenderer {
|
||||||
this.lastMousePosition = this.camera.toWordPostition(event.position)
|
this.lastMousePosition = this.camera.toWordPostition(event.position)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
dumpSimulation(this)
|
||||||
|
|
||||||
this.reloadSave()
|
this.reloadSave()
|
||||||
this.initKeyBindings()
|
this.initKeyBindings()
|
||||||
}
|
}
|
||||||
|
@ -222,7 +225,6 @@ export class SimulationRenderer {
|
||||||
if (!save) return
|
if (!save) return
|
||||||
if (!(save.simulation || save.camera)) return
|
if (!(save.simulation || save.camera)) return
|
||||||
|
|
||||||
this.simulation.dispose()
|
|
||||||
this.simulation = fromSimulationState(save.simulation)
|
this.simulation = fromSimulationState(save.simulation)
|
||||||
this.camera = fromCameraState(save.camera)
|
this.camera = fromCameraState(save.camera)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -11,4 +11,5 @@
|
||||||
|
|
||||||
.toast-content-container > #toast-content-icon {
|
.toast-content-container > #toast-content-icon {
|
||||||
font-size: 2em;
|
font-size: 2em;
|
||||||
|
margin: 10px;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue