diff --git a/src/modules/core/components/App.scss b/src/modules/core/components/App.scss index 796021b..9b0475f 100644 --- a/src/modules/core/components/App.scss +++ b/src/modules/core/components/App.scss @@ -15,4 +15,5 @@ body { background-color: $bg; overflow-y: auto; + overflow-x: hidden; } diff --git a/src/modules/core/components/OpenSimulation.tsx b/src/modules/core/components/OpenSimulation.tsx index 82fca30..5cc360b 100644 --- a/src/modules/core/components/OpenSimulation.tsx +++ b/src/modules/core/components/OpenSimulation.tsx @@ -34,7 +34,7 @@ const allSimulationSubject = new BehaviorSubject([]) * * It also has the side effect of sorting the simulation names. */ -const updateSimulationList = () => { +export const updateSimulationList = () => { allSimulationSubject.next(allSimulations().sort()) } diff --git a/src/modules/logic-gates/components/AddGate.tsx b/src/modules/logic-gates/components/AddGate.tsx index 38560e8..6e741bd 100644 --- a/src/modules/logic-gates/components/AddGate.tsx +++ b/src/modules/logic-gates/components/AddGate.tsx @@ -1,7 +1,7 @@ import React from 'react' import Icon from '@material-ui/core/Icon' import IconButton from '@material-ui/core/IconButton' -import { LogicGateProps } from './LogicGate' +import { LogicGateProps } from '../types/LogicGateProps' import { addGateFromTemplate } from '../helpers/addGateFromTemplate' const AddGate = ({ template }: LogicGateProps) => { diff --git a/src/modules/logic-gates/components/DeleteGate.tsx b/src/modules/logic-gates/components/DeleteGate.tsx new file mode 100644 index 0000000..0443e4b --- /dev/null +++ b/src/modules/logic-gates/components/DeleteGate.tsx @@ -0,0 +1,28 @@ +import React from 'react' +import Icon from '@material-ui/core/Icon' +import IconButton from '@material-ui/core/IconButton' +import { LogicGateProps } from '../types/LogicGateProps' +import { deleteGateFromMemory } from '../../simulation-actions/helpers/deleteSimulation' +import { getRendererSafely } from '../helpers/getRendererSafely' + +const DeleteGateIcon = ({ template }: LogicGateProps) => { + if (template.tags.includes('base')) { + return <> + } else { + return ( + + deleteGateFromMemory( + getRendererSafely(), + template.metadata.name + ) + } + > + delete + + ) + } +} + +export default DeleteGateIcon diff --git a/src/modules/logic-gates/components/GateInfo.tsx b/src/modules/logic-gates/components/GateInfo.tsx index b582871..24033fd 100644 --- a/src/modules/logic-gates/components/GateInfo.tsx +++ b/src/modules/logic-gates/components/GateInfo.tsx @@ -1,7 +1,7 @@ import React from 'react' import Icon from '@material-ui/core/Icon' import IconButton from '@material-ui/core/IconButton' -import { LogicGateProps } from './LogicGate' +import { LogicGateProps } from '../types/LogicGateProps' import { randomItem } from '../../internalisation/helpers/randomItem' const GateInfo = ({ template }: LogicGateProps) => { diff --git a/src/modules/logic-gates/components/GatePreview.tsx b/src/modules/logic-gates/components/GatePreview.tsx index e69de29..98203c6 100644 --- a/src/modules/logic-gates/components/GatePreview.tsx +++ b/src/modules/logic-gates/components/GatePreview.tsx @@ -0,0 +1,27 @@ +import React from 'react' +import { LogicGateProps } from '../types/LogicGateProps' +import { repeat } from '../../vector2/helpers/repeat' + +const gradientSmoothness = 10 + +const GatePreview = ({ template }: LogicGateProps) => { + const { fill } = template.material + + return template.material.type === 'image' ? ( + {template.metadata.name} + ) : ( +
repeat(color, gradientSmoothness)) + .flat(), + ...repeat(fill, gradientSmoothness) + ].join(',')})` + }} + /> + ) +} + +export default GatePreview diff --git a/src/modules/logic-gates/components/GateSettings.tsx b/src/modules/logic-gates/components/GateSettings.tsx index 685382c..e467df9 100644 --- a/src/modules/logic-gates/components/GateSettings.tsx +++ b/src/modules/logic-gates/components/GateSettings.tsx @@ -1,6 +1,6 @@ import React from 'react' import Icon from '@material-ui/core/Icon' -import { LogicGateProps } from './LogicGate' +import { LogicGateProps } from '../types/LogicGateProps' const GateSettings = ({ template }: LogicGateProps) => { const tags = template.tags diff --git a/src/modules/logic-gates/components/LogicGate.tsx b/src/modules/logic-gates/components/LogicGate.tsx index a3d79bf..4dcff7c 100644 --- a/src/modules/logic-gates/components/LogicGate.tsx +++ b/src/modules/logic-gates/components/LogicGate.tsx @@ -1,38 +1,14 @@ 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' import { addGateFromTemplate } from '../helpers/addGateFromTemplate' -import { repeat } from '../../vector2/helpers/repeat' - -export interface LogicGateProps { - template: GateTemplate -} - -const gradientSmoothness = 10 +import DeleteGateIcon from './DeleteGate' +import GatePreview from './GatePreview' +import { LogicGateProps } from '../types/LogicGateProps' const LogicGate = ({ template }: LogicGateProps) => { - const { fill } = template.material - - const gatePreview = - template.material.type === 'image' ? ( - {template.metadata.name} - ) : ( -
repeat(color, gradientSmoothness)) - .flat(), - ...repeat(fill, gradientSmoothness) - ].join(',')})` - }} - /> - ) - const rawName = template.metadata.name const name = `${rawName[0].toUpperCase()}${rawName.substr(1)}` @@ -43,7 +19,7 @@ const LogicGate = ({ template }: LogicGateProps) => { className="gate-preview" onClick={() => addGateFromTemplate(template)} > - {gatePreview} +
@@ -54,6 +30,7 @@ const LogicGate = ({ template }: LogicGateProps) => { +
diff --git a/src/modules/logic-gates/types/LogicGateProps.tsx b/src/modules/logic-gates/types/LogicGateProps.tsx new file mode 100644 index 0000000..76be29b --- /dev/null +++ b/src/modules/logic-gates/types/LogicGateProps.tsx @@ -0,0 +1,5 @@ +import { GateTemplate } from '../../simulation/types/GateTemplate' + +export interface LogicGateProps { + template: GateTemplate +} diff --git a/src/modules/saving/helpers/initSimulation.ts b/src/modules/saving/helpers/initSimulation.ts index 4120e64..96739fb 100644 --- a/src/modules/saving/helpers/initSimulation.ts +++ b/src/modules/saving/helpers/initSimulation.ts @@ -6,6 +6,7 @@ import { toast } from 'react-toastify' import { createToastArguments } from '../../toasts/helpers/createToastArguments' import { CurrentLanguage } from '../../internalisation/stores/currentLanguage' import { compileIc } from '../../integrated-circuits/helpers/compileIc' +import { updateLogicGateList } from '../../logic-gates/subjects/LogicGateList' /** * Inits a simulation by: @@ -34,6 +35,7 @@ export const initSimulation = (name: string, mode: simulationMode) => { if (mode === 'ic') { compileIc(state.simulation) + updateLogicGateList() } return state diff --git a/src/modules/simulation-actions/helpers/deleteSimulation.ts b/src/modules/simulation-actions/helpers/deleteSimulation.ts index 9580fdd..99adb6f 100644 --- a/src/modules/simulation-actions/helpers/deleteSimulation.ts +++ b/src/modules/simulation-actions/helpers/deleteSimulation.ts @@ -5,20 +5,89 @@ import { initSimulation } from '../../saving/helpers/initSimulation' import { defaultSimulationName } from '../../saving/constants' import { randomItem } from '../../internalisation/helpers/randomItem' import { switchTo } from '../../saving/helpers/switchTo' +import { updateLogicGateList } from '../../logic-gates/subjects/LogicGateList' +import { getTemplateSafely } from '../../logic-gates/helpers/getTemplateSafely' +import { SimulationError } from '../../errors/classes/SimulationError' +import { templateStore } from '../../saving/stores/templateStore' +import { updateSimulationList } from '../../core/components/OpenSimulation' -export const deleteSimulation = (renderer: SimulationRenderer) => { - const current = renderer.simulation.name +/** + * Deletes the current simulation + * + * @param renderer The current renderer + */ +export const deleteSimulation = ( + renderer: SimulationRenderer, + name?: string, + shouldDeleteIc = true +) => { + const toDelete = name ? name : renderer.simulation.name - const others = saveStore.ls() - removeElement(others, current) + if (toDelete === renderer.simulation.name) { + const others = saveStore.ls() + removeElement(others, toDelete) - if (!others.length) { - initSimulation(defaultSimulationName, 'project') + if (!others.length) { + initSimulation(defaultSimulationName, 'project') + } + + const switchTarget = randomItem(others) + switchTo(switchTarget) } - const switchTarget = randomItem(others) - switchTo(switchTarget) - // actually delete simulation - saveStore.delete(current) + const deleted = saveStore.delete(toDelete) + + if (shouldDeleteIc && deleted.simulation.mode === 'ic') { + deleteGateFromMemory(renderer, toDelete, false) + } else { + updateLogicGateList() + } + + updateSimulationList() +} + +/** + * Deletes a gate from memory + * + * @param renderer The current renderer + * @param name The name of the gate + * + * @throws SimulationError if the gate cannot be deleted + */ +export const deleteGateFromMemory = ( + renderer: SimulationRenderer, + name: string, + shouldDeleteSimulation = true +) => { + const template = getTemplateSafely(name) + + if (template.tags.includes('base')) { + throw new SimulationError('Cannot delete base gate') + } + + templateStore.delete(name) + + if (shouldDeleteSimulation && saveStore.get(name)) { + deleteSimulation(renderer, name, false) + } + + // delete all occurance of that gate + for (const simulationName of saveStore.ls()) { + const simulationState = saveStore.get(simulationName) + + if (!simulationState) { + throw new SimulationError( + `Cannot find simulation ${simulationName}` + ) + } + + simulationState.simulation.gates = simulationState.simulation.gates.filter( + gate => gate.template !== name + ) + + saveStore.set(simulationName, simulationState) + } + + updateLogicGateList() } diff --git a/src/modules/storage/classes/LocalStore.ts b/src/modules/storage/classes/LocalStore.ts index 3ccafae..90eb082 100644 --- a/src/modules/storage/classes/LocalStore.ts +++ b/src/modules/storage/classes/LocalStore.ts @@ -53,9 +53,12 @@ export class LocalStore { public delete(key = 'index') { const all = this.getAll() + const last = all[key] delete all[key] localStorage.setItem(this.name, JSON.stringify(all)) + + return last } }