From 3a8dbd63f0ab4ae76fdefbacec61f072fb708c7b Mon Sep 17 00:00:00 2001 From: Nathan Parikh Date: Mon, 11 Sep 2017 16:17:34 -0500 Subject: [PATCH] Separated markup, logic, and styling. Also fixed issue #3 --- css/app.css | 336 ++++++++++++++++++++++ index.html | 712 +---------------------------------------------- js/app_common.js | 336 ++++++++++++++++++++++ 3 files changed, 686 insertions(+), 698 deletions(-) create mode 100644 css/app.css create mode 100644 js/app_common.js diff --git a/css/app.css b/css/app.css new file mode 100644 index 0000000..86024b0 --- /dev/null +++ b/css/app.css @@ -0,0 +1,336 @@ +body { + background: rgba(0, 0, 0, 0.95); + font-family: 'Inconsolata', monospace; + color: #fff; + margin-top: 5px; +} +ul { + margin: 0; + padding: 0; +} +.titlebar { + -webkit-user-select: none; + -webkit-app-region: drag; + opacity: 0; +} + .titlebar:hover { + opacity: 1; + } + .titlebar .controls { + float: right; + line-height: 0; + } +button { + -webkit-app-region: no-drag; + background: none; + border: none; + outline: none; +} + +#close-btn, +#min-btn { + height: 12px; + width: 12px; + background: none; + border: 2px solid #000; + -moz-border-radius: 50px; + -webkit-border-radius: 50px; + border-radius: 50px; + padding: 0; +} +#close-btn { + border-color: #ff2626; +} + #close-btn:hover { + background: #ff2626; + } +#min-btn { + border-color: #ffbd45; +} + #min-btn:hover { + background: #ffbd45; + } +#settings-btn { + padding: 0; + +} +#settings-btn img { + width: 24px; + opacity: 0.5; +} + #settings-btn:hover img { + opacity: 1; + } + +ul { + list-style-type: none; +} + #prices { + margin: 0; + padding: 0; + font-size: 28px; + font-weight: 400; + } + #prices li { + margin: 0px 0px 15px 0px; + padding: 0px 0px 15px 0px; + border-bottom: 1px solid #252525; + } + #prices li:last-child { + border-bottom: none; + } + #prices li span { + + } + #prices li span.draggable { + width: 100%; + } + #prices li .sym { + border: 1px solid #252525; + border-left-width: 2px; + padding: 0px 5px 0px; + font-family: 'Heebo', sans-serif; + font-size: 12px; + } + #prices li .sym:hover { + cursor: -webkit-grab; + } + /*Symbol Colors*/ + #prices li#coin-BTC .sym { + border-left-color: #F9A847; + } + #prices li#coin-XRP .sym { + border-left-color: #0997D2; + } + #prices li#coin-LTC .sym { + border-left-color: #F1F1F1; + } + #prices li#coin-NEO .sym, + #prices li#coin-GAS .sym { + border-left-color: #9CD115; + } + #prices li#coin-OMG .sym { + border-left-color: #1A53F0; + } + #prices li#coin-BCH .sym { + border-left-color: #F7931A; + } + #prices li#coin-DASH .sym { + border-left-color: #0475B6; + } + #prices li#coin-XMR .sym { + border-left-color: #FF6600; + } + #prices li#coin-ETC .sym { + border-left-color: #689274; + } + #prices li#coin-ZEC .sym { + border-left-color: #EFB948; + } + #prices li#coin-GNT .sym { + border-left-color: #00AFBF; + } + #prices li#coin-BAT .sym { + border-left-color: #662F92; + } + #prices li#coin-FCT .sym { + border-left-color: #E3A77D; + } + #prices li#coin-ARK .sym { + border-left-color: #CB0101; + } + #prices li#coin-DOGE .sym { + border-left-color: #BBA034; + } + #prices li#coin-CVC .sym { + border-left-color: #41BB2E; + } + #prices li#coin-MCO .sym { + border-left-color: #82344C; + } + #prices li#coin-UBQ .sym { + border-left-color: #00EA90; + } + #prices li#coin-DNT .sym { + border-left-color: #7CF7FA; + } + #prices li .change { + padding: 2px 3px 2px; + font-size: 12px; + float: right; + margin: 10px 0px 0px; + background: #000; + } + #prices li .change.positive { + color: #b2ff93; + } + #prices li .change.negative { + color: #ff6765; + } + + .active { + display: block; + } + .inactive { + display: none; + } + + /*Settings Page*/ + #settings h3:first-child { + margin-top: 5px; + } + #myInput { + font-family: 'Inconsolata', monospace; + border: none; + padding: 0px 0px 10px; + font-size: 14px; + background: rgba(0, 0, 0, 0); + color: #fff; + outline: none; + border-bottom: 1px solid #252525; + display: block; + width: 100%; + } + #saveCoins { + background-color: #000000; + color: #fff; + border: 1px solid #252525; + padding: 5px 10px; + margin: -1px 0px 0px 0px; + font-family: 'Inconsolata', monospace; + } + #coinlist { + margin: 15px 0px 0px 0px; + padding: 0; + max-height: 218px; + overflow-y: scroll; + } + #coinlist li { + position: relative; + margin: 0px 0px 5px 0px; + } + /* Custom checkboxes inspired by https://codepen.io/sderoij/pen/VvJJwE */ + #coinlist label { + height: auto; + width: 100%; + z-index: 0; + display: inline-block; + position: absolute; + top: 0; + left: 0; + text-indent: 24px; + } + #coinlist label div { + height: 12px; + width: 12px; + border: solid 2px rgba(255, 255, 255, 0.6); + margin: 0; + border-radius: 50%; + transform: rotate(45deg); + transition: all 0ms ease-in-out, border 0ms ease 0ms; + position: absolute; + top: 0; + } + #coinlist input:hover + label div { + border-color: rgba(138, 255, 131, 0.9); + } + #coinlist input { + height: auto; + width: 18px; + margin: 0; + opacity: 0; + z-index: 1; + position: relative; + cursor: pointer; + } + #coinlist input:checked + label > div { + border-radius: 0; + border-top: 0; + border-left: 0; + border-color: rgba(138, 255, 131, 0.9); + height: 15px; + width: 12px; + margin-top: -4px; + margin-left: 0px; + transform: rotate(40deg); + transition: all 0ms ease-in-out; + } + #tips { + font-size: 12px; + } + #tips li { + + } + + .creds { + font-size: 8px; + color: #252525; + margin: 15px 0px 0px 0px; + } + .creds a { + text-decoration: none; + color: #252525; + } + + /*Scrollbar*/ + ::-webkit-scrollbar-corner { + background-color: #000; + } + ::-webkit-scrollbar { + background-color: rgba(0, 0, 0, 100); + } + ::-webkit-scrollbar { + width: .5em; + height: .5em; + } + + ::-webkit-scrollbar-thumb:window-inactive, + ::-webkit-scrollbar-thumb { + background: #252525; + -webkit-border-radius: 100px; + } + + /*Select Boxes*/ + .custom-select { + position: relative; + display: inline-block; + } + .custom-select select { + display: inline-block; + border: 1px solid #252525; + padding: 4px 3px 3px 5px; + margin: 0; + font: inherit; + outline: none; + line-height: 1.2; + background: #000000; + -webkit-appearance: none; + width: 145px; + color: #fff; + } + /* for Webkit's CSS-only solution */ + @media screen and (-webkit-min-device-pixel-ratio:0) { + .custom-select select { + padding-right:30px; + } + } + /* Since we removed the default focus styles, we have to add our own */ + .custom-select select:focus { + -webkit-box-shadow: 0 0 3px 1px #00afc1; + -moz-box-shadow: 0 0 3px 1px #00afc1; + box-shadow: 0 0 3px 1px #00afc1; + } + /* Select arrow styling */ + .custom-select:after { + content: "▼"; + position: absolute; + top: 0; + right: 0; + bottom: 0; + font-size: 60%; + line-height: 30px; + padding: 0 7px; + background: #252525; + color: white; + pointer-events: none; + } \ No newline at end of file diff --git a/index.html b/index.html index a555e5c..df5d3ca 100644 --- a/index.html +++ b/index.html @@ -5,345 +5,7 @@ Latest Crypto Prices - + @@ -353,6 +15,7 @@ +
@@ -410,370 +73,23 @@
+ + + + + + + + + + + - - + \ No newline at end of file diff --git a/js/app_common.js b/js/app_common.js new file mode 100644 index 0000000..fb9382d --- /dev/null +++ b/js/app_common.js @@ -0,0 +1,336 @@ +/****************** +* APP FUNCTIONALITY +******************/ +//user settings +const settings = require('electron-settings'); +settings.set('developer', { + first: 'Nathan', + last: 'Parikh' +}); + //default coins + if(settings.has('user.coins')) { + //do nothing because coins already set + } + else { + settings.set('user', { + coins: 'BTC,ETH,LTC' + }); + } + //default base currency + if(settings.has('user.currency')) { + //do nothing because currency already set + } + else { + settings.set('user.currency', 'USD'); + } + +(function() { + + function loadJSON(callback) { + var file = 'https://www.cryptocompare.com/api/data/coinlist/'; + var xobj = new XMLHttpRequest(); + xobj.overrideMimeType("application/json"); + xobj.open('GET', file, true); + xobj.onreadystatechange = function () { + if (xobj.readyState == 4 && xobj.status == "200") { + // Required use of an anonymous callback as .open will NOT return a value but simply returns undefined in asynchronous mode + callback(xobj.responseText); + } + }; + xobj.send(null); + } //loadJSON + + // Generate the list of all coins + loadJSON(function(response) { + // Parse JSON string into object + var myDiv = document.getElementById("coinlist"); + var actual_JSON = JSON.parse(response); + //alert(settings.get('user.coins')); + //console.log(actual_JSON.Data); + + //loop through data, get coin info, generate checkbox for each coin + Object.keys(actual_JSON.Data).forEach(function(key) { + //console.log(actual_JSON.Data[key].Name); + //console.log(actual_JSON.Data[key].CoinName); + var li = document.createElement("li"); + var checkBox = document.createElement("input"); + checkBox.className = "coinCode"; + var label = document.createElement("label"); + label.className = "coinName"; + var div = document.createElement("div"); + checkBox.type = "checkbox"; + checkBox.value = actual_JSON.Data[key].Name; + checkBox.name = "cl[]"; + //check the coins the user has already set + var str = String(settings.get('user.coins')); + var split_str = str.split(","); + if (split_str.indexOf(actual_JSON.Data[key].Name) !== -1) { + checkBox.checked = true; + } + myDiv.appendChild(li); + li.appendChild(checkBox); + li.appendChild(label); + label.appendChild(document.createTextNode(actual_JSON.Data[key].CoinName)); + label.appendChild(document.createTextNode(' ('+actual_JSON.Data[key].Name+')')); + label.appendChild(div); + }); //forEach + + }); //loadJSON + + base = settings.get('user.currency'); // get the user's base currency + var currSel = document.getElementById('base'); //select the currency select box + currSel.value = settings.get('user.currency'); //select the option that corresponds to the user's currency + setBase = function() { + //selected base currency + var sel = document.getElementById('base'); + var x = sel.selectedIndex; + var y = sel.options; + base = y[x].text; + settings.set('user.currency', base); //save the user's selection + updateData(); //immediately reflect the changed currency + }; + +})(); + +//Functions for creating/appending elements +function createNode(element) { + return document.createElement(element); +} +function append(parent, el) { + return parent.appendChild(el); +} + + +// Returns an array with values of the selected (checked) checkboxes in "frm" +function getSelectedChbox(frm) { + var selchbox = []; // array that will store the value of selected checkboxes + // gets all the input tags in frm, and their number + var inpfields = frm.getElementsByTagName('input'); + var nr_inpfields = inpfields.length; + // traverse the inpfields elements, and adds the value of selected (checked) checkbox in selchbox + for(var i=0; i ' + coinRate + '' + coinDISPLAYchange + '%'; + + // % Change + let change = document.querySelector("#coin-"+[key]+" .change"); + if(coinDISPLAYchange > 0) { + change.className += " positive"; + change.classList.remove("negative"); + } + else if(coinDISPLAYchange < 0) { + change.className += " negative"; + change.classList.remove("postive"); + } + else { + change.classList.remove("postive"); + change.classList.remove("negative"); + } + } + }); + } + ) + setTimeout(function(){updateData()}, 5000); // run this once every 5 seconds +} + +// Let's do this thing! +initData(); + +/* Test this function */ +//document.getElementById('firstname').innerHTML = settings.get('user.coins'); +// Click on #saveCoins, save the coin selection to the user +document.getElementById('saveCoins').onclick = function(){ + var coinForm = document.getElementById('coinlist'); + var selchb = getSelectedChbox(coinForm); // gets the array returned by getSelectedChbox() + //alert(selchb); + settings.set('user.coins', selchb); + + // just reloading the entire app because I have yet to figure out how to add/remove a coin from the primary list without a page reload + location.reload(false); + + //alert(settings.get('user.currency')); +} + +/******* +* APP UI +********/ + +//Window controls +const remote = require('electron').remote; +document.getElementById("close-btn").addEventListener("click", function (e) { + var window = remote.getCurrentWindow(); + window.close(); +}); +document.getElementById("min-btn").addEventListener("click", function (e) { + var window = remote.getCurrentWindow(); + window.minimize(); +}); + +//settings tab/icon +function toggleSettings() { + var divs = document.getElementsByClassName('panel'), i; + for (i = 0; i < divs.length; ++i) { + if(divs[i].classList.contains('inactive')) { + divs[i].classList.remove('inactive'); + divs[i].classList.add('active'); + } + else { + divs[i].classList.remove('active'); + divs[i].classList.add('inactive'); + } + }//for +}//toggleSettings + +//Coin search filter +function myFunction() { + // Declare variables + var input, filter, ul, li, a, i; + input = document.getElementById('myInput'); + filter = input.value.toUpperCase(); + ul = document.getElementById("coinlist"); + li = ul.getElementsByTagName('li'); + + // Loop through all list items, and hide those who don't match the search query + for (i = 0; i < li.length; i++) { + label = li[i].getElementsByTagName("label")[0]; + checkbox = li[i].getElementsByTagName("input")[0].value; + if (label.innerHTML.toUpperCase().indexOf(filter) > -1) { + li[i].style.display = ""; + } else { + li[i].style.display = "none"; + } + } //for +} //myFunction + +//sort by attribute +function sortChildren(wrap, f, isNum) { + var l = wrap.children.length, + arr = new Array(l); + for(var i=0; ib[0] ? 1 : 0; } + ); + var par = wrap.parentNode, + ref = wrap.nextSibling; + par.removeChild(wrap); + for(var i=0; i