Bläddra i källkod

Merge pull request #30 from thingsSDK/new-ui

New UI - thanks @mathelme
Andrew Chalkley 9 år sedan
förälder
incheckning
fa33cdef9c
4 ändrade filer med 192 tillägg och 144 borttagningar
  1. 4 0
      README.md
  2. 58 105
      front-end/css/style.css
  3. 46 23
      front-end/index.html
  4. 84 16
      front-end/js/app.js

+ 4 - 0
README.md

@@ -1,6 +1,9 @@
 # Flasher.js
 # Flasher.js
 [![Build Status](https://api.travis-ci.org/thingsSDK/flasher.js.svg)](https://travis-ci.org/thingsSDK/flasher.js)
 [![Build Status](https://api.travis-ci.org/thingsSDK/flasher.js.svg)](https://travis-ci.org/thingsSDK/flasher.js)
 
 
+<img src="http://thingssdk.com/flasher.js.svg" width="180px" height="180px">
+
+
 _Flasher.js_ is a tool to get JavaScript running natively on
 _Flasher.js_ is a tool to get JavaScript running natively on
 the Internet of Things device, ESP8266. This application runs on
 the Internet of Things device, ESP8266. This application runs on
 Windows, Mac OS X and Linux.
 Windows, Mac OS X and Linux.
@@ -27,6 +30,7 @@ EP-12 devices like the Adafruit Huzzah and Adadfruit Feather Huzzah.
 |[Adafruit Feather HUZZAH](https://www.adafruit.com/products/2821)|Tested|May require [driver](https://www.silabs.com/products/mcu/Pages/USBtoUARTBridgeVCPDrivers.aspx) installation. Automatically resets to bootloader mode on firmware upload.|
 |[Adafruit Feather HUZZAH](https://www.adafruit.com/products/2821)|Tested|May require [driver](https://www.silabs.com/products/mcu/Pages/USBtoUARTBridgeVCPDrivers.aspx) installation. Automatically resets to bootloader mode on firmware upload.|
 |[Adafruit HUZZAH](https://learn.adafruit.com/adafruit-huzzah-esp8266-breakout)|Tested|Requires [FTDI](https://www.adafruit.com/products/70) cable. To put device in to bootloader mode, hold `GPIO0` button while inserting USB in to your computer.|
 |[Adafruit HUZZAH](https://learn.adafruit.com/adafruit-huzzah-esp8266-breakout)|Tested|Requires [FTDI](https://www.adafruit.com/products/70) cable. To put device in to bootloader mode, hold `GPIO0` button while inserting USB in to your computer.|
 |[NodeMCU V3](http://www.banggood.com/V3-NodeMcu-Lua-WIFI-Development-Board-p-992733.html)|Tested|Requires installation of ch340g driver.  Information can be found [here](http://www.wemos.cc/tutorial/get_started_in_nodemcu.html).  For Mac there can be issues installing the driver.  Work around can be found [here](https://tzapu.com/making-ch340-ch341-serial-adapters-work-under-el-capitan-os-x/).|
 |[NodeMCU V3](http://www.banggood.com/V3-NodeMcu-Lua-WIFI-Development-Board-p-992733.html)|Tested|Requires installation of ch340g driver.  Information can be found [here](http://www.wemos.cc/tutorial/get_started_in_nodemcu.html).  For Mac there can be issues installing the driver.  Work around can be found [here](https://tzapu.com/making-ch340-ch341-serial-adapters-work-under-el-capitan-os-x/).|
+
 -------
 -------
 
 
 ## Run the GUI in Development
 ## Run the GUI in Development

+ 58 - 105
front-end/css/style.css

@@ -8,149 +8,102 @@ html {
 }
 }
 
 
 body {
 body {
-	padding: 50px;
-	font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
-	background: #333;
-	color: white;
+	font-size: 14px;
+	font-family: HelveticaNeue, "Lucida Grande", Helvetica, Arial, sans-serif;
+	color: #010101;
 }
 }
 
 
 button {
 button {
-	clear:both;
-	background: #3498db;
-	border-radius: 5px;
-	color: #fff;
-	padding: 10px 20px 10px 20px;
-	text-decoration: none;
-	border:0;
-    width: 100%;
+	background-image: linear-gradient(-180deg, #4C98FE 0%, #0664E3 100%);
+	box-shadow: 0px 0px 1px 0px rgba(0,0,0,0.15);
+	border-radius: 3px;
+	font-size: 14px;
+	color: #FFFFFF;
+	letter-spacing: -0.11px;
+	line-height: 12px;
+	height: 21px;
+	width: 60px;
+	border: 0.5px solid #247EFF;
 }
 }
 
 
 button:disabled {
 button:disabled {
 	background: #eee;
 	background: #eee;
-	color: #aaa
+	color: #aaa;
 }
 }
 
 
-
 button:hover {
 button:hover {
-	background: #3cb0fd;
-	text-decoration: none;
+	background-image: linear-gradient(-180deg, #5DA9FF 0%, #1775F4 100%);
+	box-shadow: 0px 0px 2px 0px rgba(0,0,0,0.5);
 }
 }
 
 
-button:hover:disabled {
-    background: #bbb;
-    color: #aaa
+select {
+	width: 254px;
+	height: 21px;
+	font-size: 13px;
 }
 }
 
 
 label {
 label {
-	width: 180px;
-	display: inline-block;
+	font-size: 13px;
 }
 }
 
 
-select {
-	width: 200px;
-	font-size: 15px;
-}
 footer {
 footer {
 	position:fixed;
 	position:fixed;
 	left:0;
 	left:0;
 	bottom:0;
 	bottom:0;
 	height:30px;
 	height:30px;
+	padding-top:10px;
 	width:100%;
 	width:100%;
-	background: #0568c6;
-	color: white;
+	text-align: center;
+	border-top: 1px solid #EDEAE8;
+	background: white;
 }
 }
 
 
-footer span {
-	top: 5px;
-	left: 10px;
-	position: relative;
+#app {
+	margin:27px auto;
+	display: flex;
+	background: white;
+	width: 500px;
 }
 }
 
 
-#progressBar {
-    display:none;
+#logo svg {
+	width:180px;
 }
 }
 
 
-#progress {
-	width: 0;
+#form .field {
+	margin-top:20px;
+	line-height: 1.5;
 }
 }
 
 
-#form div {
-	margin-bottom: 30px;
-	text-align: center;
-}
-#form label {
+#form .button {
+	margin-top: 10px;
 	text-align: right;
 	text-align: right;
 }
 }
-/*
-* https://css-tricks.com/examples/ProgressBars/
-*/
-.meter {
-	height: 40px;  /* Can be anything */
-	position: relative;
-	margin: 40px 0 20px 0; /* Just for demo spacing */
-	background: #555;
-	border-radius: 25px;
-	padding: 10px;
-	box-shadow: inset 0 -1px 1px rgba(255,255,255,0.3);
-}
-.meter > span {
-	display: block;
-	height: 100%;
-	border-top-right-radius: 8px;
-	border-bottom-right-radius: 8px;
-	border-top-left-radius: 20px;
-	border-bottom-left-radius: 20px;
-	background-color: rgb(5, 138, 255);
-	background-image: -webkit-gradient(
-			linear,
-			left bottom,
-			left top,
-			color-stop(0,  rgb(5, 138, 255)),
-			color-stop(1, rgb(71, 190, 240))
-	);
-
-	box-shadow:
-			inset 0 2px 9px  rgba(255,255,255,0.3),
-			inset 0 -2px 6px rgba(0,0,0,0.4);
-	position: relative;
-	overflow: hidden;
+
+@keyframes moveLeft {
+    0%   {margin-left: 0px;}
+    100% {margin-left: 160px;}
 }
 }
-.meter > span:after, .animate > span > span {
-	content: "";
-	position: absolute;
-	top: 0; left: 0; bottom: 0; right: 0;
-	background-image:
-			-webkit-gradient(linear, 0 0, 100% 100%,
-			color-stop(.25, rgba(255, 255, 255, .2)),
-			color-stop(.25, transparent), color-stop(.5, transparent),
-			color-stop(.5, rgba(255, 255, 255, .2)),
-			color-stop(.75, rgba(255, 255, 255, .2)),
-			color-stop(.75, transparent), to(transparent)
-			);
-	z-index: 1;
-	background-size: 50px 50px;
-	-webkit-animation: move 2s linear infinite;
-	border-top-right-radius: 8px;
-	border-bottom-right-radius: 8px;
-	border-top-left-radius: 20px;
-	border-bottom-left-radius: 20px;
-	overflow: hidden;
+
+@keyframes moveBack {
+    0%   {margin-left: 160px;}
+    100% {margin-left: 0px;}
+}
+
+#app.flashing #logo {
+	animation: moveLeft 500ms ease-in;
+	margin-left: 160px;
 }
 }
 
 
-.animate > span:after {
+#app.flashing #form {
 	display: none;
 	display: none;
 }
 }
 
 
-@-webkit-keyframes move {
-	0% {
-		background-position: 0 0;
-	}
-	100% {
-		background-position: 50px 50px;
-	}
+#app.finished #logo {
+	animation: moveBack 500ms ease-in;
+	margin-left: 0px;
+}
+
+#app.finished #form {
+	display: inline-block;
 }
 }
 
 
-.nostripes > span > span, .nostripes > span:after {
-	-webkit-animation: none;
-	background-image: none;
-}

+ 46 - 23
front-end/index.html

@@ -6,32 +6,55 @@
     <link rel="stylesheet" href="css/style.css">
     <link rel="stylesheet" href="css/style.css">
 </head>
 </head>
 <body>
 <body>
-<div id="form">
-    <div>
-        <label for="ports">Select Port:</label>
-        <select title="Select a Serial/COM Port" id="ports" name="ports" disabled>
+    <div id="app">
+        <div id="logo">
+            <svg version="1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+     viewBox="0 0 180 180" style="enable-background:new 0 0 180 180;" xml:space="preserve">
+        <style type="text/css">
+            .st0{fill:none;stroke:url(#SVGID_1_);stroke-width:3;stroke-miterlimit:10;}
+            .st1{fill:none;stroke:#FFAB91;stroke-width:3;stroke-miterlimit:10;}
+            .st2{fill:none;stroke:#FFD600;stroke-width:3;stroke-miterlimit:10;}
+            .bg{fill:none;stroke:#EEEEEE;stroke-width:3;stroke-miterlimit:10;}
+        </style>
+        <g>
+            <title>Flasherjs</title>
 
 
-        </select>
-    </div>
-    <div>
-        <label for="manifests">Select Binaries to Flash:</label>
-        <select title="Select Binaries to Flash" id="manifests" name="manifests" disabled>
+        <linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="49" y1="145" x2="128" y2="145" gradientTransform="matrix(1 0 0 1 0 -55)">
+            <stop  offset="0" style="stop-color:#FFAB91"/>
+            <stop  offset="1" style="stop-color:#FFD600"/>
+        </linearGradient>
 
 
-        </select>
-    </div>
-    <div>
-        <button id="flash-button" disabled>
-            Flash!
-        </button>
-    </div>
-</div>
-<div id="progressBar" class="meter animate">
-    <span id="progress"><span></span></span>
-</div>
+        <polyline class="st0" points="52,28 63,28 51,93 57,93 72,4 78,4 62,93 68,93 78,38 84,38
+        73,93 79,93 86,55 91,55 69,176 75,176 91,88 97,88 85,154 90,154 102,88 108,88
+        100,136 105,136 114,88 119,88 117,99 128,99"/>
+        <circle class="st1" cx="49" cy="28" r="3"/>
+        <circle class="st2" cx="131" cy="100" r="3"/>
+        </g>
+        </svg>
+        </div>
+        <div id="form">
+            <div class="field">
+                <label for="ports">Select Port:</label><br>
+                <select title="Select a Serial/COM Port" id="ports" name="ports" disabled>
 
 
-<footer><span id="status"></span></footer>
+                </select>
+            </div>
+            <div class="field">
+                <label for="manifests">Select Binaries to Flash:</label><br>
+                <select title="Select Binaries to Flash" id="manifests" name="manifests" disabled>
 
 
-<!-- Javascript -->
-<script src="js/app.js" charset="utf-8"></script>
+                </select>
+            </div>
+            <div class="button">
+                <button id="flash-button" disabled>
+                    Flash!
+                </button>
+            </div>
+        </div>
+    </div>
+    
+    <footer><span id="status"></span></footer>
+    <!-- Javascript -->
+    <script src="js/app.js" charset="utf-8"></script>
 </body>
 </body>
 </html>
 </html>

+ 84 - 16
front-end/js/app.js

@@ -36,8 +36,10 @@ const flashButton = $("flash-button");
 const appStatus = $("status");
 const appStatus = $("status");
 const portsSelect = new PortSelect($("ports"));
 const portsSelect = new PortSelect($("ports"));
 const manifestsSelect = $("manifests");
 const manifestsSelect = $("manifests");
-const progressHolder = $("progressBar");
-const progressBar =  $("progress");
+const svg = $("Layer_1");
+const appWrapper = $("app");
+const logoWrapper = $("logo");
+
 const form = $("form");
 const form = $("form");
 
 
 /************************
 /************************
@@ -62,17 +64,17 @@ function processJSON(response) {
     return response.json();
     return response.json();
 }
 }
 
 
-
-
 /************************
 /************************
  * Handle UI
  * Handle UI
 ************************/
 ************************/
 
 
 flashButton.addEventListener("click", (event) => {
 flashButton.addEventListener("click", (event) => {
     disableInputs();
     disableInputs();
-    fetch(manifestsSelect.value)
-        .then(processJSON)
-        .then(flashWithManifest);
+    prepareUIForFlashing(()=>{
+        fetch(manifestsSelect.value)
+            .then(processJSON)
+            .then(flashWithManifest);
+    });
 });
 });
 
 
 /************************
 /************************
@@ -101,9 +103,6 @@ serialScanner.on("error", onError);
  * Updates UI to say it's ready
  * Updates UI to say it's ready
  */
  */
 function readyToFlash() {
 function readyToFlash() {
-    updateProgressBar(0);
-    progressHolder.style.display = "none";
-    form.style.display = "block";
     appStatus.textContent = "Ready";
     appStatus.textContent = "Ready";
     enableInputs();
     enableInputs();
 }
 }
@@ -160,8 +159,6 @@ function getManifests() {
 }
 }
 
 
 function flashWithManifest(manifest) {
 function flashWithManifest(manifest) {
-    form.style.display = "none";
-    progressHolder.style.display = "block";
     appStatus.textContent = `Flashing ${portsSelect.value}`;
     appStatus.textContent = `Flashing ${portsSelect.value}`;
     const numberOfSteps = manifest.flash.length * 2;
     const numberOfSteps = manifest.flash.length * 2;
     let correctStepNumber = 1;
     let correctStepNumber = 1;
@@ -177,7 +174,7 @@ function flashWithManifest(manifest) {
             const flashPercent = Math.round((progress.details.flashedBytes/progress.details.totalBytes) * 100);
             const flashPercent = Math.round((progress.details.flashedBytes/progress.details.totalBytes) * 100);
             const processSoFar = 50; //From download and extracting.
             const processSoFar = 50; //From download and extracting.
             const flashProcess = flashPercent / 2; //To add to the overall progress
             const flashProcess = flashPercent / 2; //To add to the overall progress
-            updateProgressBar(processSoFar + flashProcess);
+            updateProgressBar(processSoFar + flashProcess, svg);
             appStatus.textContent = `${progress.display} - ${flashPercent}%`;
             appStatus.textContent = `${progress.display} - ${flashPercent}%`;
 
 
         });
         });
@@ -190,6 +187,7 @@ function flashWithManifest(manifest) {
                 .then((result) => {
                 .then((result) => {
                     new Notification("Flash Finished!");
                     new Notification("Flash Finished!");
                     readyToFlash();
                     readyToFlash();
+                    restoreUI();
                     log.info("Flashed to latest Espruino build!", result);
                     log.info("Flashed to latest Espruino build!", result);
                 });
                 });
         }).catch((error) => {
         }).catch((error) => {
@@ -200,13 +198,83 @@ function flashWithManifest(manifest) {
     }).on("entry", (progress) => {
     }).on("entry", (progress) => {
         //For the download/extract progress. The other half is flashing.
         //For the download/extract progress. The other half is flashing.
         const extractPercent = Math.round((correctStepNumber++/numberOfSteps) * 50);
         const extractPercent = Math.round((correctStepNumber++/numberOfSteps) * 50);
-        updateProgressBar(extractPercent);
+        updateProgressBar(extractPercent, svg);
         appStatus.textContent = progress.display;
         appStatus.textContent = progress.display;
     });
     });
 }
 }
 
 
-function updateProgressBar(percent) {
-    progressBar.style.width = `${percent}%`;
+function cloneSVGNode(node) {
+    return node.cloneNode(true);
+}
+
+function updateClass(node) {
+    node.setAttribute("class", "bg");
+    return node;
+}
+
+function updateProgressBar(percent, svg){
+    const line = svg.getElementsByClassName("st0")[0];
+    const startDot = svg.getElementsByClassName("st1")[0];
+    const finishDot = svg.getElementsByClassName("st2")[0];
+
+    let backgroundElements = svg.getElementsByClassName("bg");
+
+    if(backgroundElements.length === 0) {
+        const g = svg.getElementsByTagName("g")[0];
+        backgroundElements = [line, startDot, finishDot]
+                                    .map(cloneSVGNode)
+                                    .map(updateClass);
+
+        backgroundElements.forEach(node => g.insertBefore(node, line));
+    }
+
+    const bgLine = backgroundElements[0];
+
+    line.points.clear();
+    
+    if( percent < 1 ) {
+        startDot.style.opacity = 0;
+    } else {
+        startDot.style.opacity = 1;
+    }
+
+    if( percent > 99 ) {
+        finishDot.style.opacity = 1;
+    } else {
+        finishDot.style.opacity = 0;
+    }
+
+    for(var i = 0; i < percent * (bgLine.points.numberOfItems / 100); i ++) {
+        if(i < bgLine.points.numberOfItems) {
+            const point = bgLine.points.getItem(i);
+            const newPoint = svg.createSVGPoint();
+	        newPoint.x = point.x;
+            newPoint.y = point.y;
+            line.points.appendItem(newPoint);
+        }
+    }
+}
+
+function prepareUIForFlashing(callback) {
+    let percent = 100;
+    appWrapper.classList.remove("finished");
+    appWrapper.classList.add("flashing");
+    
+    let percentInterval = setInterval(() => {
+        percent -= 1;
+        updateProgressBar(percent, svg);
+        if(percent === 0) {
+            clearInterval(percentInterval);
+            if(callback) callback();
+        }
+    }, 1);
+}
+
+function restoreUI(callback) {
+    appWrapper.classList.remove("flashing");
+    appWrapper.classList.add("finished");
+    updateProgressBar(100, svg);
+    if(callback) callback();
 }
 }
 
 
 /**
 /**