🌷 automated update

This commit is contained in:
Matei Adriel 2019-05-28 18:26:14 +03:00
parent 308d608f0a
commit cf156dec78
17 changed files with 444 additions and 37 deletions

11
package-lock.json generated
View file

@ -54,6 +54,12 @@
"@types/sizzle": "*" "@types/sizzle": "*"
} }
}, },
"@types/micromodal": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@types/micromodal/-/micromodal-0.3.0.tgz",
"integrity": "sha512-n8Qicw8bPWAFJjR8HICQhgUXmTUjDZf2Yt85N0LozuOMKEYEIRMwqvTCp1A5dd5ycE5piyvERQajyUDF8SGaOw==",
"dev": true
},
"@types/minimatch": { "@types/minimatch": {
"version": "3.0.3", "version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
@ -4479,6 +4485,11 @@
"to-regex": "^3.0.2" "to-regex": "^3.0.2"
} }
}, },
"micromodal": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/micromodal/-/micromodal-0.4.0.tgz",
"integrity": "sha512-YDku9Fi57S4Sm6oitSy3sr786qSp5L6NbatuH2kEeXf0jStvZgZk4bLBKaoSONBaq3BEvFz3hAaoUa7/pV1Kgg=="
},
"miller-rabin": { "miller-rabin": {
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz",

View file

@ -24,6 +24,7 @@
"devDependencies": { "devDependencies": {
"@types/file-saver": "^2.0.1", "@types/file-saver": "^2.0.1",
"@types/gh-pages": "^2.0.0", "@types/gh-pages": "^2.0.0",
"@types/micromodal": "^0.3.0",
"@types/toastr": "^2.1.37", "@types/toastr": "^2.1.37",
"css-loader": "^2.1.0", "css-loader": "^2.1.0",
"extract-text-webpack-plugin": "^4.0.0-beta.0", "extract-text-webpack-plugin": "^4.0.0-beta.0",
@ -50,6 +51,7 @@
"haunted": "^4.3.0", "haunted": "^4.3.0",
"lit-html": "^1.0.0", "lit-html": "^1.0.0",
"lit-rx": "0.0.2", "lit-rx": "0.0.2",
"micromodal": "^0.4.0",
"prelude-ts": "^0.8.2", "prelude-ts": "^0.8.2",
"rxjs": "^6.5.2", "rxjs": "^6.5.2",
"toastr": "^2.1.4" "toastr": "^2.1.4"

BIN
src/assets/and_gate.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

View file

@ -1,4 +1,5 @@
@import "./toastr.scss"; @import "./toastr.scss";
@import "./modal.scss";
html, body { html, body {
padding: 0; padding: 0;
@ -58,3 +59,17 @@ svg {
background-color: #000000; background-color: #000000;
box-shadow: 0 0 0px black !important; box-shadow: 0 0 0px black !important;
} }
div.component-container{
display: flex;
height: 100%;
width: 100%;
flex-direction: column;
align-items: center;
justify-content: center;
img.component {
// border: 10px solid black;
border-radius: 20px;
user-select: none;
}
}

153
src/scss/modal.scss Normal file
View file

@ -0,0 +1,153 @@
/**************************\
Basic Modal Styles
\**************************/
.modal {
font-family: -apple-system,BlinkMacSystemFont,avenir next,avenir,helvetica neue,helvetica,ubuntu,roboto,noto,segoe ui,arial,sans-serif;
}
.modal__overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.6);
display: flex;
justify-content: center;
align-items: center;
}
.modal__container {
background-color: #222;
color: rgb(256,256,256);
padding: 30px;
max-width: 500px;
max-height: 100vh;
border-radius: 4px;
overflow-y: auto;
box-sizing: border-box;
}
.modal__header {
display: flex;
justify-content: space-between;
align-items: center;
}
.modal__title {
margin-top: 0;
margin-bottom: 0;
font-weight: 600;
font-size: 1.25rem;
line-height: 1.25;
color: #0099aa;
box-sizing: border-box;
}
.modal__close {
background: transparent;
border: 0;
color: white;
}
.modal__header .modal__close:before { content: "\2715"; }
.modal__content {
margin-top: 2rem;
margin-bottom: 2rem;
line-height: 1.5;
color: rgba(256,256,256,0.8);
}
.modal__btn {
font-size: .875rem;
padding-left: 1rem;
padding-right: 1rem;
padding-top: .5rem;
padding-bottom: .5rem;
background-color: #e6e6e6;
color: rgba(0,0,0,.8);
border-radius: .25rem;
border-style: none;
border-width: 0;
cursor: pointer;
-webkit-appearance: button;
text-transform: none;
overflow: visible;
line-height: 1.15;
margin: 0;
will-change: transform;
-moz-osx-font-smoothing: grayscale;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
-webkit-transform: translateZ(0);
transform: translateZ(0);
transition: -webkit-transform .25s ease-out;
transition: transform .25s ease-out;
transition: transform .25s ease-out,-webkit-transform .25s ease-out;
}
.modal__btn:focus, .modal__btn:hover {
-webkit-transform: scale(1.05);
transform: scale(1.05);
}
.modal__btn-primary {
background-color: #00449e;
color: #fff;
}
/**************************\
Demo Animation Style
\**************************/
@keyframes mmfadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes mmfadeOut {
from { opacity: 1; }
to { opacity: 0; }
}
@keyframes mmslideIn {
from { transform: translateY(15%); }
to { transform: translateY(0); }
}
@keyframes mmslideOut {
from { transform: translateY(0); }
to { transform: translateY(-10%); }
}
.micromodal-slide {
display: none;
}
.micromodal-slide.is-open {
display: block;
}
.micromodal-slide[aria-hidden="false"] .modal__overlay {
animation: mmfadeIn .3s cubic-bezier(0.0, 0.0, 0.2, 1);
}
.micromodal-slide[aria-hidden="false"] .modal__container {
animation: mmslideIn .3s cubic-bezier(0, 0, .2, 1);
}
.micromodal-slide[aria-hidden="true"] .modal__overlay {
animation: mmfadeOut .3s cubic-bezier(0.0, 0.0, 0.2, 1);
}
.micromodal-slide[aria-hidden="true"] .modal__container {
animation: mmslideOut .3s cubic-bezier(0, 0, .2, 1);
}
.micromodal-slide .modal__container,
.micromodal-slide .modal__overlay {
will-change: transform;
}

View file

@ -11,6 +11,7 @@ import { success, error } from "toastr"
import { alertOptions } from "../componentManager/alertOptions"; import { alertOptions } from "../componentManager/alertOptions";
import { WireManager } from "../wires"; import { WireManager } from "../wires";
import { runCounter } from "./runCounter"; import { runCounter } from "./runCounter";
import { Material } from "./material";
export class Component { export class Component {
private static store = new ComponentTemplateStore() private static store = new ComponentTemplateStore()
@ -21,23 +22,24 @@ export class Component {
public position = new BehaviorSubject<number[]>(null) public position = new BehaviorSubject<number[]>(null)
public scale = new BehaviorSubject<number[]>(null) public scale = new BehaviorSubject<number[]>(null)
public clicked = false public clicked = false
public id: number
public material: Material
public clickedChanges = new BehaviorSubject(false)
private mouserDelta: number[] private mouserDelta: number[]
private strokeColor = "#888888" private strokeColor = "#888888"
private inputs: number private inputs: number
private outputs: number private outputs: number
private activation: (ctx: activationContext) => any private activation: (ctx: activationContext) => any
private subscriptions:Subscription[] = [] private subscriptions: Subscription[] = []
public inputPins: Pin[] = [] public inputPins: Pin[] = []
public outputPins: Pin[] = [] public outputPins: Pin[] = []
public id: number
constructor(private template: string, constructor(private template: string,
position: [number, number] = [0, 0], position: [number, number] = [0, 0],
scale: [number, number] = [0, 0], scale: [number, number] = [0, 0],
id? : number) { id?: number) {
//set initial props //set initial props
this.position.next(position) this.position.next(position)
@ -74,14 +76,17 @@ export class Component {
}) })
this.activate() this.activate()
this.material = new Material(data.material.mode, data.material.data)
} }
public dispose(){ public dispose() {
this.subscriptions.forEach(val => val.unsubscribe()) this.subscriptions.forEach(val => val.unsubscribe())
} }
public handleMouseUp(e: MouseEvent) { public handleMouseUp(e: MouseEvent) {
this.clicked = false this.clicked = false
this.clickedChanges.next(this.clicked)
} }
private activate() { private activate() {
@ -107,6 +112,7 @@ export class Component {
mousePosition[index] - value mousePosition[index] - value
) )
this.clicked = true this.clicked = true
this.clickedChanges.next(this.clicked)
} }
handlePinClick(e: MouseEvent, pin: Pin) { handlePinClick(e: MouseEvent, pin: Pin) {
@ -149,17 +155,18 @@ export class Component {
return ((mode === "input") ? this.inputPins : this.outputPins) return ((mode === "input") ? this.inputPins : this.outputPins)
.map((val, index) => { .map((val, index) => {
const y = subscribe(this.piny(mode === "input",index)) const y = subscribe(this.piny(mode === "input", index))
const x = subscribe(this.pinx(mode === "input",pinLength)) const x = subscribe(this.pinx(mode === "input", pinLength))
const linex = subscribe(this.x.pipe(map(val => const linex = subscribe(this.x.pipe(map(val =>
val + ((mode === "input") ? -pinLength : pinLength + this.scale.value[0]) val + ((mode === "input") ? -pinLength : pinLength + this.scale.value[0])
))) )))
const middleX = subscribe(this.x.pipe(map(val => const middleX = subscribe(this.x.pipe(map(val => {
val + this.scale.value[0] / 2 const scale = this.scale.value[0]
))) return val + ((mode === "input") ? scale / 10 : 9 * scale / 10 )
})))
return svg` return svg`
<line stroke=${this.strokeColor} y1=${y} y2=${y} <line stroke=${this.strokeColor} y1=${y} y2=${y}
@ -177,7 +184,7 @@ export class Component {
`}) `})
} }
public pinx(mode = true, pinLength = 15){ public pinx(mode = true, pinLength = 15) {
return this.x.pipe( return this.x.pipe(
map(val => val + ( map(val => val + (
(mode) ? (mode) ?
@ -187,7 +194,7 @@ export class Component {
) )
} }
public piny(mode = true, index: number){ public piny(mode = true, index: number) {
const space = this.scale.value[1] / (mode ? this.inputs : this.outputs) const space = this.scale.value[1] / (mode ? this.inputs : this.outputs)
return this.y.pipe( return this.y.pipe(
map(val => val + space * (2 * index + 1) / 2) map(val => val + space * (2 * index + 1) / 2)

View file

@ -13,3 +13,5 @@ export interface activationContext {
succes: (mes: string) => any succes: (mes: string) => any
error: (mes:string) => any error: (mes:string) => any
} }
export type materialMode = "standard_image" | "color"

View file

@ -0,0 +1,39 @@
import { TemplateResult, svg, SVGTemplateResult, Part } from "lit-html";
import { Subject, BehaviorSubject } from "rxjs";
import { materialMode } from "./interfaces";
declare function require<T>(path:string):T
type partFactory = (part:Part) => void
export class Material {
private static images: {
[key: string]: string
} = {
and: require("../../../assets/and_gate.jpg")
}
private static cached = new Map()
public color = new BehaviorSubject<string>("rgba(0,0,0,0)")
constructor (public mode: materialMode,public name:string) {
const saved = Material.cached.get(mode + name)
if (saved)
return saved
else Material.cached.set(mode + name,this)
if (this.mode === "color")
this.color.next(name)
}
innerHTML (x: partFactory, y: partFactory, w: partFactory, h: partFactory) {
return svg`<foreignobject x=${x} y=${y} width=${w} height=${h}>
<div class="component-container">
<img src=${Material.images[this.name]} height="97%" width="97%" draggable=false class="component">
</div>
</foreignobject>`
}
}

View file

@ -1,7 +1,7 @@
import { Singleton } from "@eix/utils"; import { Singleton } from "@eix/utils";
import { Component } from "../component"; import { Component } from "../component";
import { Subject, BehaviorSubject, fromEvent } from "rxjs"; import { Subject, BehaviorSubject, fromEvent } from "rxjs";
import { svg, SVGTemplateResult } from "lit-html"; import { svg, SVGTemplateResult, html } from "lit-html";
import { subscribe } from "lit-rx"; import { subscribe } from "lit-rx";
import { Screen } from "../screen.ts"; import { Screen } from "../screen.ts";
import { ManagerState } from "./interfaces"; import { ManagerState } from "./interfaces";
@ -14,6 +14,10 @@ import { WireManager } from "../wires";
import { runCounter } from "../component/runCounter"; import { runCounter } from "../component/runCounter";
import { Settings } from "../store/settings"; import { Settings } from "../store/settings";
import { download } from "./download"; import { download } from "./download";
import Modal from "micromodal"
import { modal } from "../modals";
import { map } from "rxjs/operators";
@Singleton @Singleton
export class ComponentManager { export class ComponentManager {
@ -167,17 +171,57 @@ export class ComponentManager {
this.barAlpha.next("1") this.barAlpha.next("1")
} }
create() { async create() {
const elem = <HTMLInputElement>document.getElementById("nameInput") const elem = <HTMLInputElement>document.getElementById("nameInput")
this.barAlpha.next("0") this.barAlpha.next("0")
if (this.inputMode == "create") if (this.inputMode == "create") {
await this.createEmptySimulation(elem.value)
success(`Succesfully created simulation ${elem.value}`, "", this.alertOptions) success(`Succesfully created simulation ${elem.value}`, "", this.alertOptions)
}
else if (this.inputMode == "command") else if (this.inputMode == "command")
this.eval(elem.value) this.eval(elem.value)
} }
private async handleDuplicateModal(name: string) {
const result = await modal({
title: "Warning",
content: html`There was already a simulation called ${name},
are you sure you want to override it?
All you work will be lost!`
})
return result
}
public createEmptySimulation(name: string) {
const create = () => {
this.store.set(name, {
wires: [],
components: [],
position: [0, 0],
scale: [1, 1]
})
if (name !== this.name)
this.save()
this.refresh()
}
return new Promise(async (res, rej) => {//get wheater theres already a simulation with that name
if (this.store.get(name) && await this.handleDuplicateModal(name) ||
!this.store.get(name)) {
create()
res(true)
}
})
}
public switchTo(name: string) {
//TODO: implement
}
eval(command: string) { eval(command: string) {
if (!this.commandHistory.includes(command)) // no duplicates if (!this.commandHistory.includes(command)) // no duplicates
this.commandHistory.push(command) this.commandHistory.push(command)
@ -265,26 +309,42 @@ export class ComponentManager {
let toRemoveDuplicatesFor: Component let toRemoveDuplicatesFor: Component
const size = 10 const size = 10
const result = this.components.map(component => svg` const result = this.components.map(component => {
const mouseupHandler = (e: MouseEvent) => {
component.handleMouseUp(e)
toRemoveDuplicatesFor = component
}
const stroke = subscribe(component.clickedChanges.pipe(map(
val => val ? "yellow" : "black"
)))
return svg`
<g> <g>
${component.pinsSvg(10, 20)} ${component.pinsSvg(10, 20)}
${component.pinsSvg(10, 20, "output")} ${component.pinsSvg(10, 20, "output")}
<rect width=${ subscribe(component.width)} <g @mousedown=${ (e: MouseEvent) => component.handleClick(e)}
height=${ subscribe(component.height)} @mouseup=${mouseupHandler}>
x=${ subscribe(component.x)} <rect width=${ subscribe(component.width)}
y=${ subscribe(component.y)} height=${ subscribe(component.height)}
fill="red" x=${ subscribe(component.x)}
stroke="black" y=${ subscribe(component.y)}
rx=20 stroke=${stroke}
ry=20 fill=${(component.material.mode === "standard_image") ?
@mousedown=${ (e: MouseEvent) => component.handleClick(e)} "rgba(0,0,0,0)" :
@mouseup=${(e: MouseEvent) => { subscribe(component.material.color)}
component.handleMouseUp(e) rx=20
toRemoveDuplicatesFor = component ry=20>
}}></rect> </rect>
${(component.material.mode === "standard_image") ? component.material.innerHTML(
subscribe(component.x),
subscribe(component.y),
subscribe(component.width),
subscribe(component.height)) : ""}
</g>
</g> </g>
`); `});
if (toRemoveDuplicatesFor) if (toRemoveDuplicatesFor)
this.removeDuplicates(toRemoveDuplicatesFor) this.removeDuplicates(toRemoveDuplicatesFor)

View file

@ -72,7 +72,11 @@ export class ComponentTemplateStore {
version: "1.0.0", version: "1.0.0",
activation: ` activation: `
ctx.outputs[0].value = ctx.inputs[0].value ctx.outputs[0].value = ctx.inputs[0].value
`.trim() `.trim(),
material: {
mode: "color",
data: "blue"
}
}) })
this.store.set("not", { this.store.set("not", {
inputs: 1, inputs: 1,
@ -81,7 +85,11 @@ export class ComponentTemplateStore {
version: "1.0.0", version: "1.0.0",
activation: ` activation: `
ctx.outputs[0].value = !ctx.inputs[0].value ctx.outputs[0].value = !ctx.inputs[0].value
`.trim() `.trim(),
material: {
mode: "color",
data: "red"
}
}) })
this.store.set("and", { this.store.set("and", {
inputs: 2, inputs: 2,
@ -90,7 +98,11 @@ export class ComponentTemplateStore {
version: "1.0.0", version: "1.0.0",
activation: ` activation: `
ctx.outputs[0].value = ctx.inputs[0].value && ctx.inputs[1].value ctx.outputs[0].value = ctx.inputs[0].value && ctx.inputs[1].value
`.trim() `.trim(),
material: {
mode: "standard_image",
data: "and"
}
}) })
this.store.set("true", { this.store.set("true", {
inputs: 0, inputs: 0,
@ -99,7 +111,11 @@ export class ComponentTemplateStore {
version: "1.0.0", version: "1.0.0",
activation: ` activation: `
ctx.outputs[0].value = true ctx.outputs[0].value = true
`.trim() `.trim(),
material:{
mode:"color",
data:"green"
}
}) })
} }
} }

View file

@ -1,4 +1,4 @@
import { ComponentState } from "../component/interfaces"; import { ComponentState, materialMode } from "../component/interfaces";
import { WireState } from "../wires/interface"; import { WireState } from "../wires/interface";
export interface ManagerState { export interface ManagerState {
@ -14,4 +14,8 @@ export interface ComponentTemplate {
activation: string activation: string
inputs: number inputs: number
outputs: number outputs: number
material: {
mode: materialMode
data: string
}
} }

View file

@ -0,0 +1 @@
export * from "./modal"

View file

@ -0,0 +1,8 @@
import { TemplateResult } from "lit-html";
export interface confirmModalOptions {
title: string
content: TemplateResult
yes: string
no: string
}

View file

@ -0,0 +1,83 @@
import { render, html } from "lit-html"
import { confirmModalOptions } from "./interfaces";
import { fromEvent } from "rxjs";
import MicroModal from "micromodal"
let lastId = 0
export const modal = (options: Partial<confirmModalOptions>) => new Promise((res, rej) => {
const defaultOptions = {
yes: "yes",
no: "no",
title: "modal",
content: html`Hello world!`
}
const parent = document.getElementsByClassName("ModalContainer")[0]
const finalOptions: confirmModalOptions = { ...defaultOptions, ...options }
const id = lastId++
if (!parent)
rej(false)
const template = html`
<div class="modal micromodal-slide" id="modal-${id}" aria-hidden="true">
<div class="modal__overlay" tabindex="-1" data-micromodal-close>
<div class="modal__container" role="dialog" aria-modal="true" aria-labelledby="modal-1-title">
<header class="modal__header">
<h2 class="modal__title" id="modal-${id}-title">
${finalOptions.title}
</h2>
<button class="modal__close" aria-label="Close modal" data-micromodal-close></button>
</header>
<main class="modal__content" id="modal-${id}-content">
${finalOptions.content}
</main>
<footer class="modal__footer">
<button class="modal__btn" id="yes-${id}">${finalOptions.yes}</button>
<button class="modal__btn modal__btn-primary" id="no-${id}" aria-label="Close this dialog window">
${finalOptions.no}
</button>
</footer>
</div>
</div>
</div>
</div>
`
render(template, parent)
const yes = document.getElementById(`yes-${id}`)
const no = document.getElementById(`no-${id}`)
const clear = () => {
// render(html``,parent)
MicroModal.close()
subscriptions.forEach(val => val.unsubscribe())
}
const subscriptions = [
fromEvent(yes, "click").subscribe(val => {
clear()
res(true)
}),
fromEvent(no, "click").subscribe(val => {
clear()
res(false)
})
]
MicroModal.show(`modal-${id}`)
})

View file

@ -6,6 +6,10 @@ import { success, error } from "toastr"
export class Settings { export class Settings {
version = "1.0.0" version = "1.0.0"
settings = {
jumpToNewSimulations: true
}
commands = (ctx: ComponentManager, args: string[], flags: string[]) => { commands = (ctx: ComponentManager, args: string[], flags: string[]) => {
//important flags //important flags
for (let i of flags) { for (let i of flags) {

View file

@ -56,6 +56,8 @@ render(html`
${ subscribe(manager.svgs) } ${ subscribe(manager.svgs) }
</svg> </svg>
</div> </div>
<div class="ModalContainer"></div>
`, document.body) `, document.body)
manager.update() manager.update()

View file

@ -19,7 +19,7 @@ module.exports = {
] ]
}, },
{ {
test: /\.(png|mp3|wav)$/, test: /\.(png|jpg|mp3|wav)$/,
use: [ use: [
{ {
loader: 'file-loader', loader: 'file-loader',