diff --git a/frontend/assets/css/src/style.scss b/frontend/assets/css/src/style.scss new file mode 100644 index 0000000..91e31a1 --- /dev/null +++ b/frontend/assets/css/src/style.scss @@ -0,0 +1,102 @@ +$button-color: rgb(147, 146, 146); +$main-color: rgb(240, 141, 25); + +*{ + margin:0; + padding: 0; + box-sizing: border-box; +} +body{ + font-family: Roboto; + +} +main{ + position: relative; + height: 100vh; + + #infobar{ + position: absolute; + top:0; + width: 100%; + padding: 0.4em; + background-color: rgba(232, 9, 9, 0.4); + border: 4px solid rgba(232, 9, 9, 0.8); + text-align: center; + font-weight: bold; + font-size: 1.8em; + z-index: 1; + transform: translateY(-100%); + transition: transform 1s; + &.active{ + transform: translateY(0%); + } + } + + .canvas{ + background-color: lightgrey; + position: relative; + height: 100%; + + input{ + position: absolute; + border: none; + padding: 0.6em 1em; + width: 50px; + transform: translateX(-50%) translateY(-50%); + } + } + + nav, footer{ + display: flex; + position: absolute; + top: 1em; + left: 1em; + opacity: 0.9; + + button{ + display: block; + background-color: $button-color; + border: none; + border-radius: 1em; + padding: 1em 1em; + min-width: 8em; + margin: 0.4em; + color: black; + border: solid 2px darken($button-color, 50); + box-shadow: 2px 2px 8px rgba(0,0,0,0.5); + + &:focus { + outline: none; + } + &::-moz-focus-inner { + border: 0; + } + &:hover{ + background-color: lighten($button-color, 10); + border-color: darken($button-color, 100); + cursor: pointer; + } + &.active{ + background-color: $main-color; + } + h1{ + text-align: center; + font-size: 1.4em; + font-weight: normal; + + white-space: nowrap + } + img{ + display: block; + margin: 0 auto 0.5em auto; + width: 2em; + } + } + } + footer{ + top: auto; + left: auto; + bottom: 1em; + right: 1em; + } +} diff --git a/frontend/assets/css/style.min.css b/frontend/assets/css/style.min.css new file mode 100644 index 0000000..aee426d --- /dev/null +++ b/frontend/assets/css/style.min.css @@ -0,0 +1 @@ +*{margin:0;padding:0;box-sizing:border-box}body{font-family:Roboto}main{position:relative;height:100vh}main #infobar{position:absolute;top:0;width:100%;padding:0.4em;background-color:rgba(232,9,9,0.4);border:4px solid rgba(232,9,9,0.8);text-align:center;font-weight:bold;font-size:1.8em;z-index:1;transform:translateY(-100%);transition:transform 1s}main #infobar.active{transform:translateY(0%)}main .canvas{background-color:lightgrey;position:relative;height:100%}main .canvas input{position:absolute;border:none;padding:0.6em 1em;width:50px;transform:translateX(-50%) translateY(-50%)}main nav,main footer{display:flex;position:absolute;top:1em;left:1em;opacity:0.9}main nav button,main footer button{display:block;background-color:#939292;border:none;border-radius:1em;padding:1em 1em;min-width:8em;margin:0.4em;color:black;border:solid 2px #131313;box-shadow:2px 2px 8px rgba(0,0,0,0.5)}main nav button:focus,main footer button:focus{outline:none}main nav button::-moz-focus-inner,main footer button::-moz-focus-inner{border:0}main nav button:hover,main footer button:hover{background-color:#acacac;border-color:#000;cursor:pointer}main nav button.active,main footer button.active{background-color:#f08d19}main nav button h1,main footer button h1{text-align:center;font-size:1.4em;font-weight:normal;white-space:nowrap}main nav button img,main footer button img{display:block;margin:0 auto 0.5em auto;width:2em}main footer{top:auto;left:auto;bottom:1em;right:1em} diff --git a/frontend/assets/fonts/Roboto-Regular.eot b/frontend/assets/fonts/Roboto-Regular.eot new file mode 100644 index 0000000..b06f366 Binary files /dev/null and b/frontend/assets/fonts/Roboto-Regular.eot differ diff --git a/frontend/assets/fonts/Roboto-Regular.svg b/frontend/assets/fonts/Roboto-Regular.svg new file mode 100644 index 0000000..1c8971f --- /dev/null +++ b/frontend/assets/fonts/Roboto-Regular.svg @@ -0,0 +1,11080 @@ + + + + +Created by FontForge 20190801 at Wed Mar 29 14:03:00 2017 + By Jimmy Wärting +Copyright 2011 Google Inc. All Rights Reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/assets/fonts/Roboto-Regular.ttf b/frontend/assets/fonts/Roboto-Regular.ttf new file mode 100644 index 0000000..586d062 Binary files /dev/null and b/frontend/assets/fonts/Roboto-Regular.ttf differ diff --git a/frontend/assets/fonts/Roboto-Regular.woff b/frontend/assets/fonts/Roboto-Regular.woff new file mode 100644 index 0000000..bb7f7b4 Binary files /dev/null and b/frontend/assets/fonts/Roboto-Regular.woff differ diff --git a/frontend/assets/fonts/Roboto-Regular.woff2 b/frontend/assets/fonts/Roboto-Regular.woff2 new file mode 100644 index 0000000..c817ca4 Binary files /dev/null and b/frontend/assets/fonts/Roboto-Regular.woff2 differ diff --git a/frontend/assets/fonts/roboto.css b/frontend/assets/fonts/roboto.css new file mode 100644 index 0000000..a8d4398 --- /dev/null +++ b/frontend/assets/fonts/roboto.css @@ -0,0 +1,12 @@ +@font-face { + font-family: 'Roboto-Regular'; + src: url('Roboto-Regular.eot'); + src: url('Roboto-Regular.eot?#iefix') format('embedded-opentype'), + url('Roboto-Regular.svg#Roboto-Regular') format('svg'), + url('Roboto-Regular.ttf') format('truetype'), + url('Roboto-Regular.woff') format('woff'), + url('Roboto-Regular.woff2') format('woff2'); + font-weight: normal; + font-style: normal; +} + diff --git a/frontend/assets/imgs/drawing.svg b/frontend/assets/imgs/drawing.svg new file mode 100644 index 0000000..2788490 --- /dev/null +++ b/frontend/assets/imgs/drawing.svg @@ -0,0 +1,133 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/assets/imgs/link.svg b/frontend/assets/imgs/link.svg new file mode 100644 index 0000000..0eecc82 --- /dev/null +++ b/frontend/assets/imgs/link.svg @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/assets/imgs/plus.svg b/frontend/assets/imgs/plus.svg new file mode 100644 index 0000000..abc77de --- /dev/null +++ b/frontend/assets/imgs/plus.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/assets/imgs/share.svg b/frontend/assets/imgs/share.svg new file mode 100644 index 0000000..1eee8b5 --- /dev/null +++ b/frontend/assets/imgs/share.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/assets/js/canvas.js b/frontend/assets/js/canvas.js new file mode 100644 index 0000000..913644f --- /dev/null +++ b/frontend/assets/js/canvas.js @@ -0,0 +1,436 @@ +const canvas = document.getElementById("canvas"); + +// Layouts +var width = canvas.offsetWidth; +var height = canvas.offsetHeight; + +const node_size = 55; + +var stage = new Konva.Stage({ + container: canvas, + width: width, + height: height +}); + +const node_layout = { + radius: node_size, + fill: 'white', + stroke: 'black', + strokeWidth: 2, + shadowColor: 'black', + shadowBlur: 10, + shadowOffset: { + x: 2, + y: 2 + }, + shadowOpacity: 0.3, +}; + +const node_text_layout = { + x: 1 - node_size, + y: 2 - node_size, + text: name, + fontSize: 22, + width: 2 * node_size-1, + height: 2 * node_size-1, + fontFamily: 'Roboto', + fill: 'black', + verticalAlign: 'middle', + align: 'center' +}; + +const edge_layout = { + stroke: 'black', + strokeWidth: 3, +} + +const edge_text_layout = { + fontSize: 22, + width: 2 * node_size, + height: 2 * node_size, + fontFamily: 'Roboto', + fill: 'black', + verticalAlign: 'middle', + align: 'center' +}; + +//----------------------------------------------------------------------------- +//-------------------------------Init------------------------------------------ +//----------------------------------------------------------------------------- +var edge_layer = new Konva.Layer(); +var node_layer = new Konva.Layer(); + +var konva_edges = []; +var konva_nodes = []; +var graph_copy = {}; + +var state = "idle"; + +// selected nodes +var selected = []; +var path_elements = []; + +// (additions) auto layout +var auto_layout = false; + +function initialisation(){ + stage.add(edge_layer); + stage.add(node_layer); + + // avoid flickering + edge_layer.hide(); + + // draw initial graph + for (id in nodes) { + draw_new_node(nodes[id], node_size + Math.random() * (width - 2 * node_size), node_size + Math.random() * (height - 2 * node_size)); + } + for (id in edges) { + draw_new_edge(edges[id]); + } + + // (additions) auto layout + + if ( sessionStorage.getItem("auto_layout") !== null) { + // Restore the contents of the text field + auto_layout = (sessionStorage.getItem("auto_layout") == 'true'); + if (auto_layout){ + document.querySelector("[data-activeon=auto_layout]").classList.add("active"); + } + } + // Precalculate a good graph presentation + for (var i = 0; i < 1000; i++) { + force_directed_graph(); + } + node_layer.draw(); + + + edge_layer.show(); + +} +initialisation(); +//----------------------------------------------------------------------------- +//------------------------------utils------------------------------------------ +//----------------------------------------------------------------------------- +function sort(array) { + return array.sort(function(a, b) { + return a - b; + }) +} +//----------------------------------------------------------------------------- +//---------------------------draw methods-------------------------------------- +//----------------------------------------------------------------------------- +function draw_new_node(name, x, y) { + const pos = { + x: x, + y: y + }; + let group = new Konva.Group({ + ...pos, + draggable: true, + dragBoundFunc: function(pos) { + return { + x: sort([node_size, pos.x, width - node_size])[1], + y: sort([node_size, pos.y, height - node_size])[1], + }; + }, + id: name + }); + let box = new Konva.Circle(node_layout); + let simpleText = new Konva.Text({...node_text_layout, text: name}); + group.add(box); + group.add(simpleText); + group.on("click", on_node_click); + group.on('dragstart', function() { + group.attrs.dragging = true; + }); + group.on('dragend', function() { + group.attrs.dragging = false; + }); + group.on('mouseover', function() { + document.body.style.cursor = 'pointer'; + }); + group.on('mouseout', function() { + document.body.style.cursor = 'default'; + }); + graph_copy[name] = []; + konva_nodes.push(group); + + node_layer.add(group); + node_layer.draw(); +} + + +function draw_new_edge(edge) { + let start_node = stage.findOne('#' + edge["start"]); + let end_node = stage.findOne('#' + edge["end"]); + let weight = edge["weight"]; + let group = new Konva.Group({ + start_node: start_node, + end_node: end_node, + weight: weight, + id: edge["start"]+edge["end"] + }); + let line = new Konva.Line(edge_layout); + let simpleText = new Konva.Text({...edge_text_layout, text: weight}); + + graph_copy[edge["start"]].push(edge["end"]); + graph_copy[edge["end"]].push(edge["start"]); + + group.add(line); + group.add(simpleText); + konva_edges.push(group); + update_edge(group); + + edge_layer.add(group); + edge_layer.draw(); + + return group; +} + +function update_edge(konva_edge) { + let line = konva_edge.children[0]; + let text = konva_edge.children[1]; + let start_node = konva_edge.attrs.start_node; + let end_node = konva_edge.attrs.end_node; + let size = 15+text.text().length*15; + let line_length = Math.sqrt((start_node.getX() - end_node.getX()) ** 2 + (start_node.getY() - end_node.getY()) ** 2) - size; + line.points([start_node.getX(), start_node.getY(), end_node.getX(), end_node.getY()]); + line.dash([line_length / 2, size, line_length / 2]); + text.x((start_node.getX() + end_node.getX()) / 2 - node_size); + text.y((start_node.getY() + end_node.getY()) / 2 - node_size), + + edge_layer.draw(); +} + +function reset_node_style(){ + for (let id in konva_nodes) { + konva_nodes[id].children[0].strokeWidth(node_layout.strokeWidth); + konva_nodes[id].children[0].stroke("black"); + } +} + +function reset_edge_style(){ + for (let id in konva_edges) { + konva_edges[id].children[0].strokeWidth(edge_layout.strokeWidth); + konva_edges[id].children[0].stroke("black"); + } +} + +function draw_selected_nodes() { + reset_node_style(); + reset_edge_style(); + for (let id in selected) { + selected[id].children[0].strokeWidth(node_layout.strokeWidth + 1); + selected[id].children[0].stroke("rgb(240, 141, 25)"); + } + node_layer.draw(); +} + +function draw_path(path){ + let path_elements = []; + for (let id in path){ + path_elements.push(stage.findOne("#"+path[id])); + if (id == 0) { + continue + } + let current_edge = stage.findOne("#"+path[id-1]+path[id]); + if (current_edge){ + path_elements.push(current_edge); + }else{ + path_elements.push(stage.findOne("#"+path[id]+path[id-1])); + } + } + reset_node_style(); + reset_edge_style(); + for (let id in path_elements) { + path_elements[id].children[0].strokeWidth(node_layout.strokeWidth + 1); + path_elements[id].children[0].stroke("rgb(240, 141, 25)"); + } +} + +function on_node_click(e) { + e.cancelBubble = true; + // let mousePos = stage.getPointerPosition(); + let idx = selected.indexOf(this); + if (idx >= 0) { + selected.splice(idx, 1); + } else if (selected.length < 2) { + selected.push(this); + } else { + selected.shift(); + selected.push(this); + } + draw_selected_nodes(); +}; + + + +function create_node(){ + if (state != "create_node"){ + state = "create_node"; + // let mousePos = stage.getPointerPosition(); + let pos = {x: width/2, y: height/2}; + create_input(pos.x, pos.y).then(function(text) { + draw_new_node(text, pos.x, pos.y); + state = "idle"; + }, function(){state = "idle"}); + } +} + + +function create_edge() { + if (selected.length < 2) { + show_error("Select at least 2 nodes."); + return; + } + let x = (selected[0].getX() + selected[1].getX()) / 2; + let y = (selected[0].getY() + selected[1].getY()) / 2; + create_input(x, y).then(function(text) { + draw_new_edge({ + "start": selected[0].children[1].text(), + "end": selected[1].children[1].text(), + "weight": text + }); + selected = []; + draw_selected_nodes(); + },function(){}); +} + + +function create_input(x, y) { + return new Promise(function(resolve, reject) { + var input = document.createElement("input"); + input.setAttribute("type", "text"); + input.style.left = x + "px"; + input.style.top = y + "px"; + canvas.appendChild(input); + input.focus(); + stage.listening(false); + window.addEventListener("keyup", function(event) { + if (event.key === "Escape") { + input.remove(); + stage.listening(true); + reject(); + } + }); + input.addEventListener("keyup", function(event) { + if (event.key === "Enter") { + resolve(input.value); + input.remove(); + stage.listening(true); + } + }); + }); +} + +function find_path(){ + draw_path(elem); +} + +function update_edges(edges) { + for (id in edges) { + update_edge(edges[id]); + } +} +node_layer.on('beforeDraw', function() { + update_edges(konva_edges); +}); + +// adapt the stage on any window resize +function fitStageIntoParentContainer() { + width = canvas.offsetWidth; + height = canvas.offsetHeight; + stage.width(canvas.offsetWidth); + stage.height(canvas.offsetHeight); + stage.draw(); +} +window.addEventListener('resize', fitStageIntoParentContainer); + +//----------------------------------------------------------------------------- +//---------------------(additions) auto layout--------------------------------- +//----------------------------------------------------------------------------- + +function toggle_auto_layout() { + auto_layout = !auto_layout; + document.querySelector("[data-activeon=auto_layout]").classList.toggle("active"); + sessionStorage.setItem("auto_layout", auto_layout); +} + +function normalize(vec) { + let l = Math.sqrt(vec[0]**2+vec[1]**2); + return [vec[0]/l,vec[1]/l]; +} + +function in_edges(start_node, end_node){ + let idx = graph_copy[start_node.attrs.id].indexOf(end_node.attrs.id); + if (idx < 0){ + return false; + } + return true; +} + +function force_directed_graph(spring_length = 300, step = 0.004){ + for (var idx in konva_nodes){ + if (konva_nodes[idx].attrs.dragging){ + continue + } + var x1 = konva_nodes[idx].getX(); + var y1 = konva_nodes[idx].getY(); + + var rep = [0,0]; + var attr = [0,0]; + for (let jdx in konva_nodes){ + if (idx == jdx){ + continue; + } + + let x2 = konva_nodes[jdx].getX(); + let y2 = konva_nodes[jdx].getY(); + let dir = normalize([x2-x1,y2-y1]); + let dist = ((x1-x2)**2+(y1-y2)**2); + if (in_edges(konva_nodes[idx], konva_nodes[jdx])){ + let f = (dist/spring_length); + attr[0] += f*dir[0]; + attr[1] += f*dir[1]; + } + let f = (spring_length**2/Math.sqrt(dist)); + rep[0] -= f*dir[0]; + rep[1] -= f*dir[1]; + } + let new_x = x1+step*(rep[0]+attr[0]); + let new_y = y1+step*(rep[1]+attr[1]); + if (new_x < 2*node_size) { + new_x += 10*step*((2*node_size-new_x)); + } else if (new_x > width-2*node_size) { + new_x += 10*step*((width-2*node_size-new_x)); + } + if (new_y < 2*node_size) { + new_y += 10*step*((2*node_size-new_y)); + } else if (new_y > height-2*node_size) { + new_y += 10*step*((height-2*node_size-new_y)); + } + konva_nodes[idx].x(new_x); + konva_nodes[idx].y(new_y); + } +} + +var anim = new Konva.Animation(function(frame) { + if (auto_layout) { + const spring_length = 300; + const step = 0.00025*frame.timeDiff; + force_directed_graph(spring_length, step) + } +}, node_layer); +anim.start(); + + +function show_error(msg){ + let infobar = document.querySelector("#infobar"); + infobar.innerHTML = msg; + infobar.classList.add("active"); + window.setTimeout(function(){ infobar.classList.remove("active"); }, 4000); +} + +// bug: this avoids glitches +window.onfocus = function () {auto_layout = true;}; +window.onblur = function () {auto_layout = false;}; diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 0000000..d6659db --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,61 @@ + + + + + Assignment + + + + + +
+
You have to select at least 2 nodes
+
+ + +
+ + + + diff --git a/main.py b/main.py index b2d8d80..ce310df 100644 --- a/main.py +++ b/main.py @@ -2,6 +2,8 @@ from flask import Flask, jsonify, request, render_template import numpy as np app = Flask(__name__) +app.template_folder = "frontend/" +app.static_folder = "frontend/assets/" class Graph(object): diff --git a/templates/index.html b/templates/index.html deleted file mode 100644 index 172f754..0000000 --- a/templates/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - Assignment - - -

nodes: {{ nodes }}

-

edges: {{ edges }}

-
- - -