mirror of
https://github.com/nathanp/crypto-price-widget.git
synced 2025-12-06 09:22:32 -05:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b34ab0f32c | ||
|
|
276a52f87c | ||
|
|
7f0829f8ad | ||
|
|
386deb7a10 | ||
|
|
0f1b2b3d86 | ||
|
|
6da0f8f5bd | ||
|
|
1207f6a09d | ||
|
|
0f92fb17f5 | ||
|
|
3a8dbd63f0 |
@@ -36,10 +36,6 @@ Crypto Price Widget is an open source side project. To support development and k
|
||||
|
||||
No, Crypto Price Widget is completely client-side and doesn't hold any keys. All code is open source.
|
||||
|
||||
**How will you make money?**
|
||||
|
||||
I won't, but donations are welcome :)
|
||||
|
||||
**When can I have a Linux version?**
|
||||
|
||||
Linux coming soon!
|
||||
|
||||
408
css/app.css
Normal file
408
css/app.css
Normal file
@@ -0,0 +1,408 @@
|
||||
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;
|
||||
}
|
||||
|
||||
.tabs button {
|
||||
padding: 0;
|
||||
}
|
||||
.tabs button,
|
||||
.tabs button.active {
|
||||
display: inline-block;
|
||||
}
|
||||
.tabs button img {
|
||||
width: 19px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
.tabs button:hover img,
|
||||
.tabs button.active img {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#portfolio-btn, #main-btn {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.panel {
|
||||
display: none;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
}
|
||||
.coin-list {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 28px;
|
||||
font-weight: 400;
|
||||
}
|
||||
#portfolio-list.coin-list {
|
||||
font-size: 16px;
|
||||
padding-top: 9px;
|
||||
}
|
||||
.coin-list li {
|
||||
margin: 0px 0px 15px 0px;
|
||||
padding: 0px 0px 15px 0px;
|
||||
border-bottom: 1px solid #252525;
|
||||
}
|
||||
#portfolio-list.coin-list li {
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
.coin-list li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
.coin-list li span {
|
||||
|
||||
}
|
||||
.coin-list li span.draggable {
|
||||
width: 100%;
|
||||
}
|
||||
.coin-list input[type="number"] {
|
||||
border: none;
|
||||
padding: 5px;
|
||||
background: rgba(0, 0, 0, 0);
|
||||
color: #fff;
|
||||
max-width: 85px;
|
||||
display: inline-block;
|
||||
outline: none;
|
||||
}
|
||||
.coin-list .block {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
.coin-list .block label {
|
||||
font-size: 12px;
|
||||
display: block;
|
||||
/*background: rgba(255, 255, 255, 0.1);*/
|
||||
|
||||
padding: 1px 2px 2px;
|
||||
}
|
||||
.coin-list .block .quantity-value {
|
||||
color: #b2ff93;
|
||||
}
|
||||
.coin-list li .sym {
|
||||
border: 1px solid #252525;
|
||||
border-left-width: 2px;
|
||||
padding: 0px 5px 0px;
|
||||
font-family: 'Heebo', sans-serif;
|
||||
font-size: 12px;
|
||||
}
|
||||
.coin-list li .sym:hover {
|
||||
cursor: -webkit-grab;
|
||||
}
|
||||
/*Symbol Colors*/
|
||||
.coin-list li#coin-BTC .sym {
|
||||
border-left-color: #F9A847;
|
||||
}
|
||||
.coin-list li#coin-XRP .sym {
|
||||
border-left-color: #0997D2;
|
||||
}
|
||||
.coin-list li#coin-LTC .sym {
|
||||
border-left-color: #F1F1F1;
|
||||
}
|
||||
.coin-list li#coin-NEO .sym,
|
||||
.coin-list li#coin-GAS .sym {
|
||||
border-left-color: #9CD115;
|
||||
}
|
||||
.coin-list li#coin-OMG .sym {
|
||||
border-left-color: #1A53F0;
|
||||
}
|
||||
.coin-list li#coin-BCH .sym {
|
||||
border-left-color: #F7931A;
|
||||
}
|
||||
.coin-list li#coin-DASH .sym {
|
||||
border-left-color: #0475B6;
|
||||
}
|
||||
.coin-list li#coin-XMR .sym {
|
||||
border-left-color: #FF6600;
|
||||
}
|
||||
.coin-list li#coin-ETC .sym {
|
||||
border-left-color: #689274;
|
||||
}
|
||||
.coin-list li#coin-ZEC .sym {
|
||||
border-left-color: #EFB948;
|
||||
}
|
||||
.coin-list li#coin-GNT .sym {
|
||||
border-left-color: #00AFBF;
|
||||
}
|
||||
.coin-list li#coin-BAT .sym {
|
||||
border-left-color: #662F92;
|
||||
}
|
||||
.coin-list li#coin-FCT .sym {
|
||||
border-left-color: #E3A77D;
|
||||
}
|
||||
.coin-list li#coin-ARK .sym {
|
||||
border-left-color: #CB0101;
|
||||
}
|
||||
.coin-list li#coin-DOGE .sym {
|
||||
border-left-color: #BBA034;
|
||||
}
|
||||
.coin-list li#coin-CVC .sym {
|
||||
border-left-color: #41BB2E;
|
||||
}
|
||||
.coin-list li#coin-MCO .sym {
|
||||
border-left-color: #82344C;
|
||||
}
|
||||
.coin-list li#coin-UBQ .sym {
|
||||
border-left-color: #00EA90;
|
||||
}
|
||||
.coin-list li#coin-DNT .sym {
|
||||
border-left-color: #7CF7FA;
|
||||
}
|
||||
.coin-list li .change {
|
||||
padding: 2px 3px 2px;
|
||||
font-size: 12px;
|
||||
float: right;
|
||||
margin: 10px 0px 0px;
|
||||
background: #000;
|
||||
}
|
||||
.coin-list li .change.positive {
|
||||
color: #b2ff93;
|
||||
}
|
||||
.coin-list 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,
|
||||
#saveQuantities {
|
||||
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 */
|
||||
.checkbox-wrapper {
|
||||
position: relative;
|
||||
display: block;
|
||||
margin: 15px 0px 0px;
|
||||
}
|
||||
|
||||
#coinlist label,
|
||||
.checkbox-styled-label {
|
||||
height: auto;
|
||||
width: 100%;
|
||||
z-index: 0;
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
text-indent: 24px;
|
||||
}
|
||||
#coinlist label div,
|
||||
.checkbox-styled-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,
|
||||
.checkbox-styled:hover + label div {
|
||||
border-color: rgba(138, 255, 131, 0.9);
|
||||
}
|
||||
#coinlist input,
|
||||
.checkbox-styled {
|
||||
height: auto;
|
||||
width: 18px;
|
||||
margin: 0;
|
||||
opacity: 0;
|
||||
z-index: 1;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
#coinlist input:checked + label > div,
|
||||
.checkbox-styled: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;
|
||||
}
|
||||
.checkbox-styled:checked + label > div {
|
||||
width: 8px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
#tips {
|
||||
font-size: 12px;
|
||||
}
|
||||
#tips li {
|
||||
|
||||
}
|
||||
|
||||
.creds {
|
||||
font-size: 8px;
|
||||
color: #252525;
|
||||
margin: 15px 0px 0px 0px;
|
||||
}
|
||||
.creds a {
|
||||
text-decoration: none;
|
||||
color: #252525;
|
||||
}
|
||||
|
||||
/*Portfolio*/
|
||||
#portfolio-total-value {
|
||||
text-align: center;
|
||||
font-size: 1.5em;
|
||||
font-weight: 600;
|
||||
margin: 15px 0px;
|
||||
}
|
||||
#portfolioChart {
|
||||
max-height: 480px;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/*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;
|
||||
}
|
||||
108
css/offline-language-english.css
Normal file
108
css/offline-language-english.css
Normal file
@@ -0,0 +1,108 @@
|
||||
/* line 6, ../sass/_content.sass */
|
||||
.offline-ui .offline-ui-retry:before {
|
||||
content: "Reconnect";
|
||||
}
|
||||
/* line 11, ../sass/_content.sass */
|
||||
.offline-ui.offline-ui-up .offline-ui-content:before {
|
||||
content: "Your computer is connected to the internet.";
|
||||
}
|
||||
@media (max-width: 1024px) {
|
||||
/* line 11, ../sass/_content.sass */
|
||||
.offline-ui.offline-ui-up .offline-ui-content:before {
|
||||
content: "Your device is connected to the internet.";
|
||||
}
|
||||
}
|
||||
@media (max-width: 568px) {
|
||||
/* line 11, ../sass/_content.sass */
|
||||
.offline-ui.offline-ui-up .offline-ui-content:before {
|
||||
content: "Your device is connected.";
|
||||
}
|
||||
}
|
||||
/* line 22, ../sass/_content.sass */
|
||||
.offline-ui.offline-ui-down .offline-ui-content:before {
|
||||
content: "Your computer lost its internet connection.";
|
||||
}
|
||||
@media (max-width: 1024px) {
|
||||
/* line 22, ../sass/_content.sass */
|
||||
.offline-ui.offline-ui-down .offline-ui-content:before {
|
||||
content: "Your device lost its internet connection.";
|
||||
}
|
||||
}
|
||||
@media (max-width: 568px) {
|
||||
/* line 22, ../sass/_content.sass */
|
||||
.offline-ui.offline-ui-down .offline-ui-content:before {
|
||||
content: "Your device isn't connected.";
|
||||
}
|
||||
}
|
||||
/* line 33, ../sass/_content.sass */
|
||||
.offline-ui.offline-ui-down.offline-ui-connecting .offline-ui-content:before, .offline-ui.offline-ui-down.offline-ui-connecting-2s .offline-ui-content:before {
|
||||
content: "Attempting to reconnect...";
|
||||
}
|
||||
/* line 42, ../sass/_content.sass */
|
||||
.offline-ui.offline-ui-down.offline-ui-waiting .offline-ui-content[data-retry-in-unit="second"]:before {
|
||||
content: "Connection lost. Reconnecting in " attr(data-retry-in-value) " seconds...";
|
||||
}
|
||||
@media (max-width: 568px) {
|
||||
/* line 42, ../sass/_content.sass */
|
||||
.offline-ui.offline-ui-down.offline-ui-waiting .offline-ui-content[data-retry-in-unit="second"]:before {
|
||||
content: "Reconnecting in " attr(data-retry-in-value) "s...";
|
||||
}
|
||||
}
|
||||
/* line 50, ../sass/_content.sass */
|
||||
.offline-ui.offline-ui-down.offline-ui-waiting .offline-ui-content[data-retry-in-unit="second"][data-retry-in-value="1"]:before {
|
||||
content: "Connection lost. Reconnecting in " attr(data-retry-in-value) " second...";
|
||||
}
|
||||
@media (max-width: 568px) {
|
||||
/* line 50, ../sass/_content.sass */
|
||||
.offline-ui.offline-ui-down.offline-ui-waiting .offline-ui-content[data-retry-in-unit="second"][data-retry-in-value="1"]:before {
|
||||
content: "Reconnecting in " attr(data-retry-in-value) "s...";
|
||||
}
|
||||
}
|
||||
/* line 58, ../sass/_content.sass */
|
||||
.offline-ui.offline-ui-down.offline-ui-waiting .offline-ui-content[data-retry-in-unit="minute"]:before {
|
||||
content: "Connection lost. Reconnecting in " attr(data-retry-in-value) " minutes...";
|
||||
}
|
||||
@media (max-width: 568px) {
|
||||
/* line 58, ../sass/_content.sass */
|
||||
.offline-ui.offline-ui-down.offline-ui-waiting .offline-ui-content[data-retry-in-unit="minute"]:before {
|
||||
content: "Reconnecting in " attr(data-retry-in-value) "m...";
|
||||
}
|
||||
}
|
||||
/* line 66, ../sass/_content.sass */
|
||||
.offline-ui.offline-ui-down.offline-ui-waiting .offline-ui-content[data-retry-in-unit="minute"][data-retry-in-value="1"]:before {
|
||||
content: "Connection lost. Reconnecting in " attr(data-retry-in-value) " minute...";
|
||||
}
|
||||
@media (max-width: 568px) {
|
||||
/* line 66, ../sass/_content.sass */
|
||||
.offline-ui.offline-ui-down.offline-ui-waiting .offline-ui-content[data-retry-in-unit="minute"][data-retry-in-value="1"]:before {
|
||||
content: "Reconnecting in " attr(data-retry-in-value) "m...";
|
||||
}
|
||||
}
|
||||
/* line 74, ../sass/_content.sass */
|
||||
.offline-ui.offline-ui-down.offline-ui-waiting .offline-ui-content[data-retry-in-unit="hour"]:before {
|
||||
content: "Connection lost. Reconnecting in " attr(data-retry-in-value) " hours...";
|
||||
}
|
||||
@media (max-width: 568px) {
|
||||
/* line 74, ../sass/_content.sass */
|
||||
.offline-ui.offline-ui-down.offline-ui-waiting .offline-ui-content[data-retry-in-unit="hour"]:before {
|
||||
content: "Reconnecting in " attr(data-retry-in-value) "h...";
|
||||
}
|
||||
}
|
||||
/* line 82, ../sass/_content.sass */
|
||||
.offline-ui.offline-ui-down.offline-ui-waiting .offline-ui-content[data-retry-in-unit="hour"][data-retry-in-value="1"]:before {
|
||||
content: "Connection lost. Reconnecting in " attr(data-retry-in-value) " hour...";
|
||||
}
|
||||
@media (max-width: 568px) {
|
||||
/* line 82, ../sass/_content.sass */
|
||||
.offline-ui.offline-ui-down.offline-ui-waiting .offline-ui-content[data-retry-in-unit="hour"][data-retry-in-value="1"]:before {
|
||||
content: "Reconnecting in " attr(data-retry-in-value) "h...";
|
||||
}
|
||||
}
|
||||
/* line 90, ../sass/_content.sass */
|
||||
.offline-ui.offline-ui-down.offline-ui-reconnect-failed-2s.offline-ui-waiting .offline-ui-retry {
|
||||
display: none;
|
||||
}
|
||||
/* line 93, ../sass/_content.sass */
|
||||
.offline-ui.offline-ui-down.offline-ui-reconnect-failed-2s .offline-ui-content:before {
|
||||
content: "Connection attempt failed.";
|
||||
}
|
||||
75
css/offline-theme-dark-indicator.css
Normal file
75
css/offline-theme-dark-indicator.css
Normal file
@@ -0,0 +1,75 @@
|
||||
/* line 3, ../sass/_offline-theme-base-indicator.sass */
|
||||
.offline-ui, .offline-ui *, .offline-ui:before, .offline-ui:after, .offline-ui *:before, .offline-ui *:after {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* line 6, ../sass/_offline-theme-base-indicator.sass */
|
||||
.offline-ui {
|
||||
display: none;
|
||||
position: fixed;
|
||||
background: white;
|
||||
z-index: 2000;
|
||||
display: inline-block;
|
||||
}
|
||||
/* line 13, ../sass/_offline-theme-base-indicator.sass */
|
||||
.offline-ui .offline-ui-retry {
|
||||
display: none;
|
||||
}
|
||||
/* line 16, ../sass/_offline-theme-base-indicator.sass */
|
||||
.offline-ui.offline-ui-up {
|
||||
display: block;
|
||||
}
|
||||
/* line 19, ../sass/_offline-theme-base-indicator.sass */
|
||||
.offline-ui.offline-ui-down {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* line 8, ../sass/offline-theme-dark-indicator.sass */
|
||||
.offline-ui {
|
||||
-webkit-box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15);
|
||||
-moz-box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15);
|
||||
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15);
|
||||
-webkit-border-radius: 4px 4px 0 0;
|
||||
-moz-border-radius: 4px 4px 0 0;
|
||||
-ms-border-radius: 4px 4px 0 0;
|
||||
-o-border-radius: 4px 4px 0 0;
|
||||
border-radius: 4px 4px 0 0;
|
||||
font-family: "Helvetica Neue", sans-serif;
|
||||
font-weight: 300;
|
||||
padding: 1em;
|
||||
background: black;
|
||||
color: #cccccc;
|
||||
bottom: 0;
|
||||
left: 20px;
|
||||
}
|
||||
/* line 19, ../sass/offline-theme-dark-indicator.sass */
|
||||
.offline-ui .offline-ui-content {
|
||||
padding-left: 1.5em;
|
||||
}
|
||||
/* line 22, ../sass/offline-theme-dark-indicator.sass */
|
||||
.offline-ui .offline-ui-content:after {
|
||||
-webkit-border-radius: 50%;
|
||||
-moz-border-radius: 50%;
|
||||
-ms-border-radius: 50%;
|
||||
-o-border-radius: 50%;
|
||||
border-radius: 50%;
|
||||
content: " ";
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 1em;
|
||||
margin: auto;
|
||||
height: 0.8em;
|
||||
width: 0.8em;
|
||||
}
|
||||
/* line 36, ../sass/offline-theme-dark-indicator.sass */
|
||||
.offline-ui.offline-ui-up .offline-ui-content:after {
|
||||
background: #80d580;
|
||||
}
|
||||
/* line 41, ../sass/offline-theme-dark-indicator.sass */
|
||||
.offline-ui.offline-ui-down .offline-ui-content:after {
|
||||
background: #e24949;
|
||||
}
|
||||
BIN
images/icons8-Home-64.png
Normal file
BIN
images/icons8-Home-64.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 600 B |
BIN
images/icons8-Rebalance Portfolio-100.png
Normal file
BIN
images/icons8-Rebalance Portfolio-100.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.7 KiB |
745
index.html
745
index.html
@@ -5,345 +5,7 @@
|
||||
<title>Latest Crypto Prices</title>
|
||||
<link href="https://fonts.googleapis.com/css?family=Heebo:100,400" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Inconsolata" rel="stylesheet">
|
||||
<style type="text/css">
|
||||
/*@import url('https://rsms.me/interface/interface.css');*/
|
||||
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;
|
||||
}
|
||||
</style>
|
||||
<link href="css/app.css" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@@ -351,16 +13,20 @@
|
||||
<div class="controls">
|
||||
<button id="min-btn"></button>
|
||||
<button id="close-btn"></button>
|
||||
</div>
|
||||
<button id="settings-btn" onclick="toggleSettings()"><img src="images/icons8-Settings.png"></button>
|
||||
</div><!-- .controls -->
|
||||
<div class="tabs">
|
||||
<button id="main-btn" href="#main"><img src="images/icons8-Home-64.png"></button>
|
||||
<button id="portfolio-btn" href="#portfolio"><img src="images/icons8-Rebalance Portfolio-100.png"></button>
|
||||
<button id="settings-btn" href="#settings"><img src="images/icons8-Settings.png"></button>
|
||||
</div><!-- .tabs -->
|
||||
</header>
|
||||
|
||||
<div id="main" class="panel active">
|
||||
<ul id="prices">
|
||||
<ul id="prices" class="coin-list">
|
||||
</ul>
|
||||
</div><!-- #main -->
|
||||
|
||||
<div id="settings" class="panel inactive">
|
||||
<div id="settings" class="panel">
|
||||
<h3>Choose Your Coins</h3>
|
||||
|
||||
<div id="coinsearch">
|
||||
@@ -396,6 +62,15 @@
|
||||
<option value="ZAR">ZAR</option>
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<div class="checkbox-wrapper">
|
||||
<input id="pin-to-top" class="checkbox-styled" type="checkbox" name="pin-to-top">
|
||||
<label class="checkbox-styled-label">
|
||||
Window always on top?
|
||||
<div></div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
||||
<h3>Tip Jar</h3>
|
||||
<ul id="tips">
|
||||
@@ -410,370 +85,36 @@
|
||||
</div>
|
||||
</div><!-- #settings -->
|
||||
|
||||
<div id="portfolio" class="panel">
|
||||
<div class="chart">
|
||||
|
||||
</div>
|
||||
|
||||
<ul id="portfolio-list" class="coin-list">
|
||||
|
||||
</ul>
|
||||
|
||||
<button type="button" id="saveQuantities">Save</button>
|
||||
|
||||
<div id="portfolio-total-value">Total Value: <span class="value"></span></div>
|
||||
|
||||
<div class="chart-container" style="position: relative; height:40vh; width:94vw">
|
||||
<canvas id="portfolioChart" width="360" height="360"></canvas>
|
||||
</div>
|
||||
|
||||
<!-- show what % each coin is of portfolio -->
|
||||
|
||||
<!-- Enter avg. purchase price for each coin -->
|
||||
<!-- See % gain/loss -->
|
||||
</div><!-- #portfolio -->
|
||||
|
||||
</body>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require('./renderer.js')
|
||||
</script>
|
||||
|
||||
<script>
|
||||
/******************
|
||||
* 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<nr_inpfields; i++) {
|
||||
if(inpfields[i].type == 'checkbox' && inpfields[i].checked == true) selchbox.push(inpfields[i].value);
|
||||
}
|
||||
return selchbox;
|
||||
}
|
||||
|
||||
/* 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
|
||||
});
|
||||
|
||||
var selectedCoins = settings.get('user.coins');
|
||||
//document.getElementById('firstname').innerHTML = selectedCoins;
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
const ul = document.getElementById('prices'); // Get the list where we will place coins
|
||||
const url = 'https://min-api.cryptocompare.com/data/pricemultifull?fsyms='+settings.get('user.coins') +'&tsyms='+base +'&extraParams=your_app_name';
|
||||
|
||||
function initData() {
|
||||
fetch(url)
|
||||
.then(
|
||||
function(response) {
|
||||
if (response.status !== 200) {
|
||||
console.log('Looks like there was a problem. Status Code: ' +
|
||||
response.status);
|
||||
return;
|
||||
}
|
||||
|
||||
// Examine the response
|
||||
response.json().then(function(data) {
|
||||
//console.log(data);
|
||||
let prices = data.DISPLAY;
|
||||
var i = 0;
|
||||
for (let key of Object.keys(prices)) {
|
||||
let coin = prices[key];
|
||||
//console.log(coin);
|
||||
let li = createNode('li'),
|
||||
span = createNode('span');
|
||||
sym = createNode('span');
|
||||
li.setAttribute("class", "price");
|
||||
li.setAttribute("id", "coin-"+[key]);
|
||||
//alert("coin-"+[key])
|
||||
//console.log(settings.get('coin.'+[key]+'.order'));
|
||||
li.setAttribute("sortorder", settings.get(li.id+'.order'));
|
||||
//alert(settings.get(li.id+'.order'));
|
||||
append(li, span);
|
||||
append(ul, li);
|
||||
i++;
|
||||
}
|
||||
//console.log(data.RAW.BTC.USD.PRICE)
|
||||
|
||||
sortChildren(
|
||||
document.getElementById('prices'),
|
||||
function(li) { return +li.getAttribute('sortorder') }
|
||||
);
|
||||
|
||||
//sort your coins
|
||||
sortable('#prices', {
|
||||
handle: 'span'
|
||||
})[0].addEventListener('sortstop', function(e) {
|
||||
// Declare variables
|
||||
var ul, li, i;
|
||||
ul = document.getElementById("prices");
|
||||
li = ul.getElementsByTagName('li');
|
||||
|
||||
// Loop through all list items
|
||||
for (i = 0; i < li.length; i++) {
|
||||
li[i].setAttribute("sortorder", i);
|
||||
var elementID = li[i].id;
|
||||
//alert(elementID);
|
||||
settings.set(elementID, { // coin-BTC
|
||||
order: li[i].getAttribute('sortorder')
|
||||
});
|
||||
//alert(settings.get(elementID + '.order'));
|
||||
}
|
||||
//alert(settings.get('coin.'+e+'.order'));
|
||||
|
||||
/*
|
||||
This event is triggered when the user stopped sorting and the DOM position has changed.
|
||||
|
||||
e.detail.item contains the current dragged element.
|
||||
e.detail.index contains the new index of the dragged element (considering only list items)
|
||||
e.detail.oldindex contains the old index of the dragged element (considering only list items)
|
||||
e.detail.elementIndex contains the new index of the dragged element (considering all items within sortable)
|
||||
e.detail.oldElementIndex contains the old index of the dragged element (considering all items within sortable)
|
||||
e.detail.startparent contains the element that the dragged item comes from
|
||||
e.detail.endparent contains the element that the dragged item was added to (new parent)
|
||||
e.detail.newEndList contains all elements in the list the dragged item was dragged to
|
||||
e.detail.newStartList contains all elements in the list the dragged item was dragged from
|
||||
e.detail.oldStartList contains all elements in the list the dragged item was dragged from BEFORE it was dragged from it
|
||||
*/
|
||||
}); //sortable
|
||||
|
||||
}); //response.json
|
||||
} //function(response)
|
||||
) //.then
|
||||
.catch(function(err) {
|
||||
console.log('Fetch Error :-S', err);
|
||||
});
|
||||
updateData();
|
||||
}
|
||||
|
||||
function updateData() {
|
||||
const url = 'https://min-api.cryptocompare.com/data/pricemultifull?fsyms='+settings.get('user.coins') +'&tsyms='+base +'&extraParams=your_app_name';
|
||||
fetch(url)
|
||||
.then(
|
||||
function(response) {
|
||||
if (response.status !== 200) {
|
||||
console.log('Looks like there was a problem. Status Code: ' +
|
||||
response.status);
|
||||
return;
|
||||
}
|
||||
// Examine the text in the response
|
||||
response.json().then(function(data) {
|
||||
let pricesDISPLAY = data.DISPLAY; // display for everything except coin symbol
|
||||
let pricesRAW = data.RAW; // raw to get BTC instead of bitcoin symbol
|
||||
for (let key of Object.keys(pricesRAW)) {
|
||||
let coinDISPLAY = pricesDISPLAY[key];
|
||||
let coinDISPLAYchange = coinDISPLAY[base].CHANGEPCT24HOUR;
|
||||
let coinRAW = pricesRAW[key];
|
||||
//console.log(coinDISPLAY);
|
||||
let li = document.getElementById("coin-"+[key]),
|
||||
span = document.querySelector("#coin-"+[key]+" span");
|
||||
span.setAttribute("class", "draggable");
|
||||
|
||||
let coinSymbol = coinRAW[base].FROMSYMBOL;
|
||||
let coinRate = coinDISPLAY[base].PRICE.replace(/ /g,''); //.replace(/ /g,'') removes space after $
|
||||
|
||||
//replace currencies that have no symbols with easier to read formats
|
||||
if(coinRate.includes("AUD")) { coinRate = coinRate.replace("AUD", "A$"); }
|
||||
if(coinRate.includes("CAD")) { coinRate = coinRate.replace("CAD", "C$"); }
|
||||
if(coinRate.includes("HKD")) { coinRate = coinRate.replace("HKD", "HK$"); }
|
||||
if(coinRate.includes("MXN")) { coinRate = coinRate.replace("MXN", "$"); }
|
||||
if(coinRate.includes("NOK")) { coinRate = coinRate.replace("NOK", "kr"); }
|
||||
if(coinRate.includes("NZD")) { coinRate = coinRate.replace("NZD", "NZ$"); }
|
||||
if(coinRate.includes("SEK")) { coinRate = coinRate.replace("SEK", "kr"); }
|
||||
if(coinRate.includes("SGD")) { coinRate = coinRate.replace("SGD", "S$"); }
|
||||
if(coinRate.includes("TRY")) { coinRate = coinRate.replace("TRY", "₺"); }
|
||||
if(coinRate.includes("ZAR")) { coinRate = coinRate.replace("ZAR", "R"); }
|
||||
|
||||
//console.log(span);
|
||||
span.innerHTML = '<span class="sym">' + coinSymbol + '</span> ' + coinRate + '<span class="change">' + coinDISPLAYchange + '%</span>';
|
||||
|
||||
// % 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();
|
||||
|
||||
/*******
|
||||
* 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; i<l; ++i)
|
||||
arr[i] = [f(wrap.children[i]), wrap.children[i]];
|
||||
arr.sort(isNum
|
||||
? function(a,b){ return a[0]-b[0]; }
|
||||
: function(a,b){ return a[0]<b[0] ? -1 : a[0]>b[0] ? 1 : 0; }
|
||||
);
|
||||
var par = wrap.parentNode,
|
||||
ref = wrap.nextSibling;
|
||||
par.removeChild(wrap);
|
||||
for(var i=0; i<l; ++i) wrap.appendChild(arr[i][1]);
|
||||
par.insertBefore(wrap, ref);
|
||||
} //sortChildren
|
||||
|
||||
</script>
|
||||
<script src="js/app_common.js"></script>
|
||||
<script src="js/html.sortable.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.0/Chart.min.js"></script>
|
||||
</html>
|
||||
533
js/app_common.js
Normal file
533
js/app_common.js
Normal file
@@ -0,0 +1,533 @@
|
||||
/******************
|
||||
* APP FUNCTIONALITY
|
||||
******************/
|
||||
//access electron from here
|
||||
const remote = require('electron').remote;
|
||||
//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<nr_inpfields; i++) {
|
||||
if(inpfields[i].type == 'checkbox' && inpfields[i].checked == true) selchbox.push(inpfields[i].value);
|
||||
}
|
||||
return selchbox;
|
||||
}
|
||||
|
||||
const ul = document.getElementById('prices'); // Get the list where we will place coins
|
||||
const portfolio_ul = document.getElementById('portfolio-list');;
|
||||
const url = 'https://min-api.cryptocompare.com/data/pricemultifull?fsyms='+settings.get('user.coins') +'&tsyms='+base +'&extraParams=crypto-price-widget';
|
||||
|
||||
var pinCheck = document.getElementById("pin-to-top");
|
||||
|
||||
function initData() {
|
||||
fetch(url)
|
||||
.then(
|
||||
function(response) {
|
||||
if (response.status !== 200) {
|
||||
console.log('Looks like there was a problem. Status Code: ' +
|
||||
response.status);
|
||||
return;
|
||||
}
|
||||
|
||||
// Examine the response
|
||||
response.json().then(function(data) {
|
||||
//console.log(data);
|
||||
let prices = data.DISPLAY;
|
||||
var i = 0;
|
||||
for (let key of Object.keys(prices)) {
|
||||
let coin = prices[key];
|
||||
//console.log(coin);
|
||||
let li = createNode('li'),
|
||||
span = createNode('span');
|
||||
sym = createNode('span');
|
||||
li.setAttribute("class", "price");
|
||||
li.setAttribute("id", "coin-"+[key]);
|
||||
//alert("coin-"+[key])
|
||||
//console.log(settings.get('coin.'+[key]+'.order'));
|
||||
li.setAttribute("sortorder", settings.get(li.id+'.order'));
|
||||
//alert(settings.get(li.id+'.order'));
|
||||
append(li, span);
|
||||
append(ul, li);
|
||||
i++;
|
||||
} //for
|
||||
//console.log(data.RAW.BTC.USD.PRICE)
|
||||
|
||||
sortChildren(
|
||||
document.getElementById('prices'),
|
||||
function(li) { return +li.getAttribute('sortorder') }
|
||||
);
|
||||
sortChildren(
|
||||
document.getElementById('portfolio-list'),
|
||||
function(li) { return +li.getAttribute('sortorder') }
|
||||
);
|
||||
|
||||
//sort your coins
|
||||
sortable('#prices', {
|
||||
handle: 'span'
|
||||
})[0].addEventListener('sortstop', function(e) {
|
||||
// Declare variables
|
||||
var ul, ulPortfolio, li, liPortfolio, i;
|
||||
ul = document.getElementById("prices");
|
||||
ulPortfolio = document.getElementById("portfolio-list");
|
||||
li = ul.getElementsByTagName('li');
|
||||
liPortfolio = ulPortfolio.getElementsByTagName('li');
|
||||
// Loop through all list items
|
||||
for (i = 0; i < li.length; i++) {
|
||||
li[i].setAttribute("sortorder", i);
|
||||
|
||||
var elementID = li[i].id;
|
||||
//alert(elementID);
|
||||
settings.set(elementID, { // coin-BTC
|
||||
order: li[i].getAttribute('sortorder')
|
||||
});
|
||||
//alert(settings.get(elementID + '.order'));
|
||||
} //for
|
||||
//alert(settings.get('coin.'+e+'.order'));
|
||||
}); //sortable
|
||||
|
||||
}); //response.json
|
||||
} //function(response)
|
||||
) //.then
|
||||
.catch(function(err) {
|
||||
console.log('Fetch Error :-S', err);
|
||||
});
|
||||
updateData();
|
||||
}
|
||||
|
||||
function updateData() {
|
||||
//console.log(settings.get('user.coins'));
|
||||
const url = 'https://min-api.cryptocompare.com/data/pricemultifull?fsyms='+settings.get('user.coins') +'&tsyms='+base +'&extraParams=crypto-price-widget';
|
||||
fetch(url)
|
||||
.then(
|
||||
function(response) {
|
||||
if (response.status !== 200) {
|
||||
console.log('Looks like there was a problem. Status Code: ' +
|
||||
response.status);
|
||||
return;
|
||||
}
|
||||
// Examine the text in the response
|
||||
response.json().then(function(data) {
|
||||
let pricesDISPLAY = data.DISPLAY; // display for everything except coin symbol
|
||||
let pricesRAW = data.RAW; // raw to get BTC instead of bitcoin symbol
|
||||
let portfolioSum = 0;
|
||||
|
||||
// Chart labels
|
||||
var chartLabels = [];
|
||||
// Chart data
|
||||
var chartData = [];
|
||||
// Chart colors - need to match these colors to the coin in a future release
|
||||
var chartColors = [
|
||||
'#FF9F1C',
|
||||
'#2EC4B6',
|
||||
'#E71D36',
|
||||
'#011627',
|
||||
'#FDFFFC',
|
||||
'#D31EE8',
|
||||
'#0288D1',
|
||||
'#5FC42D',
|
||||
'#E64A19',
|
||||
'#0097A7',
|
||||
'#FBC02D',
|
||||
'#00796B',
|
||||
'#388E3C',
|
||||
'#689F38',
|
||||
'#303F9F',
|
||||
'#C2185B',
|
||||
'#FFA000',
|
||||
'#D32F2F',
|
||||
'#C2185B',
|
||||
'#fff'
|
||||
];
|
||||
//randomize
|
||||
function shuffle(array) {
|
||||
var currentIndex = array.length, temporaryValue, randomIndex;
|
||||
|
||||
// While there remain elements to shuffle...
|
||||
while (0 !== currentIndex) {
|
||||
|
||||
// Pick a remaining element...
|
||||
randomIndex = Math.floor(Math.random() * currentIndex);
|
||||
currentIndex -= 1;
|
||||
|
||||
// And swap it with the current element.
|
||||
temporaryValue = array[currentIndex];
|
||||
array[currentIndex] = array[randomIndex];
|
||||
array[randomIndex] = temporaryValue;
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
for (let key of Object.keys(pricesRAW)) {
|
||||
let coinDISPLAY = pricesDISPLAY[key];
|
||||
let coinDISPLAYchange = coinDISPLAY[base].CHANGEPCT24HOUR;
|
||||
let coinRAW = pricesRAW[key];
|
||||
//console.log(coinDISPLAY);
|
||||
let li = document.getElementById("coin-"+[key]),
|
||||
span = document.querySelector("#coin-"+[key]+" span");
|
||||
span.setAttribute("class", "draggable");
|
||||
|
||||
let coinSymbol = coinRAW[base].FROMSYMBOL;
|
||||
let coinRate = coinDISPLAY[base].PRICE.replace(/ /g,''); //.replace(/ /g,'') removes space after $
|
||||
|
||||
//replace currencies that have no symbols with easier to read formats
|
||||
if(coinRate.includes("AUD")) { coinRate = coinRate.replace("AUD", "A$"); }
|
||||
if(coinRate.includes("CAD")) { coinRate = coinRate.replace("CAD", "C$"); }
|
||||
if(coinRate.includes("HKD")) { coinRate = coinRate.replace("HKD", "HK$"); }
|
||||
if(coinRate.includes("MXN")) { coinRate = coinRate.replace("MXN", "$"); }
|
||||
if(coinRate.includes("NOK")) { coinRate = coinRate.replace("NOK", "kr"); }
|
||||
if(coinRate.includes("NZD")) { coinRate = coinRate.replace("NZD", "NZ$"); }
|
||||
if(coinRate.includes("SEK")) { coinRate = coinRate.replace("SEK", "kr"); }
|
||||
if(coinRate.includes("SGD")) { coinRate = coinRate.replace("SGD", "S$"); }
|
||||
if(coinRate.includes("TRY")) { coinRate = coinRate.replace("TRY", "₺"); }
|
||||
if(coinRate.includes("ZAR")) { coinRate = coinRate.replace("ZAR", "R"); }
|
||||
|
||||
//console.log(span);
|
||||
span.innerHTML = '<span class="sym">' + coinSymbol + '</span> ' + coinRate + '<span class="change">' + coinDISPLAYchange + '%</span>';
|
||||
|
||||
// % 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");
|
||||
}
|
||||
|
||||
// Portfolio
|
||||
let quantityValue = document.querySelector("#coin-"+[key]+" .quantity-value");
|
||||
let quantityNumber = settings.get('quantity.'+[key]);
|
||||
let regp = /[^0-9.-]+/g;
|
||||
let quantityTotal = parseFloat(coinRate.replace(regp, '')) * parseFloat(quantityNumber.replace(regp, ''));
|
||||
|
||||
// sum of all total coin values
|
||||
portfolioSum += quantityTotal;
|
||||
// put sum into the markup
|
||||
let portfolioTotalValue = document.querySelector("#portfolio-total-value .value");
|
||||
|
||||
// total value for each coin
|
||||
if(coinRate.includes("Ƀ")) {
|
||||
//because BTC has 8 decimal places
|
||||
quantityValue.innerHTML = quantityTotal.toFixed(8);
|
||||
portfolioTotalValue.innerHTML = portfolioSum.toFixed(8);
|
||||
}
|
||||
else {
|
||||
//standard currency format
|
||||
quantityValue.innerHTML = quantityTotal.toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,');
|
||||
portfolioTotalValue.innerHTML = portfolioSum.toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,');
|
||||
}
|
||||
|
||||
// Chart labels
|
||||
chartLabels.push(key);
|
||||
// Chart data
|
||||
chartData.push(quantityTotal);
|
||||
|
||||
} //for
|
||||
|
||||
sortChildren(
|
||||
document.getElementById('portfolio-list'),
|
||||
function(li) { return +li.getAttribute('sortorder') }
|
||||
);
|
||||
|
||||
var newChartLabels = chartLabels;
|
||||
|
||||
// Chart
|
||||
var ctx = document.getElementById("portfolioChart");
|
||||
var myChart = new Chart(ctx, {
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
datasets: [{
|
||||
data: chartData,
|
||||
backgroundColor: chartColors,
|
||||
borderColor: '#000',
|
||||
borderWidth: 0
|
||||
}],
|
||||
|
||||
labels: newChartLabels
|
||||
},
|
||||
options: {
|
||||
animation : false,
|
||||
responsive: false,
|
||||
maintainAspectRatio: true,
|
||||
legend : {
|
||||
position: 'bottom'
|
||||
}
|
||||
}
|
||||
}); //myChart
|
||||
|
||||
//Pin to Top - settings check - immediately set checkbox and window to saved state
|
||||
if(settings.get('user.pinToTop') == 'yes') {
|
||||
pinCheck.checked = true;
|
||||
remote.getCurrentWindow().setAlwaysOnTop(true);
|
||||
} else {
|
||||
pinCheck.checked = false;
|
||||
remote.getCurrentWindow().setAlwaysOnTop(false);
|
||||
}
|
||||
|
||||
}); //then
|
||||
}
|
||||
)
|
||||
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'));
|
||||
}
|
||||
|
||||
/***********
|
||||
* PORTFOLIO
|
||||
***********/
|
||||
var portfolio_list_container = document.querySelector('#portfolio-list');
|
||||
var portfolio_list = settings.get('user.coins');
|
||||
|
||||
//generate html from list of coins
|
||||
for (let key of Object.keys(portfolio_list)) {
|
||||
let coin = portfolio_list[key];
|
||||
//console.log(coin);
|
||||
let li = createNode('li'),
|
||||
span = createNode('span');
|
||||
sym = createNode('span');
|
||||
li.setAttribute("id", "coin-"+[coin]);
|
||||
li.setAttribute("sortorder", settings.get(li.id+'.order'));
|
||||
|
||||
append(li, span);
|
||||
append(portfolio_ul, li);
|
||||
|
||||
if (settings.has('quantity.'+[coin])) {
|
||||
inputValue = settings.get('quantity.'+[coin]);
|
||||
}
|
||||
else {
|
||||
inputValue = '0';
|
||||
inputValue = settings.set('quantity.'+[coin], '0');
|
||||
}
|
||||
|
||||
span.innerHTML = '<span class="sym">' + coin + '</span> <span class="block quantity"><label for="quantity.' + coin +'">Quantity</label> <input type="number" name="quantity.' + coin +'" min="0" value="'+inputValue+'" step=".01"></span> <span class="block value"><label>Current Value</label><span class="quantity-value"></span></span>';
|
||||
|
||||
i++;
|
||||
} //for
|
||||
|
||||
// save quantities
|
||||
document.getElementById('saveQuantities').onclick = function(){
|
||||
var items = portfolio_ul.getElementsByTagName("input");
|
||||
for (var i = 0; i < items.length; ++i) {
|
||||
// do something with items[i], which is a <li> element
|
||||
inputName = items[i].getAttribute("name");
|
||||
inputValue = items[i].value;
|
||||
//console.log(inputValue);
|
||||
settings.set(inputName, inputValue);
|
||||
}
|
||||
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
/***********
|
||||
* PIN TO TOP
|
||||
*************/
|
||||
pinCheck.onclick = function(event) {
|
||||
var window = remote.getCurrentWindow();
|
||||
var checkbox = event.target;
|
||||
if(checkbox.checked) {
|
||||
//Checkbox has been checked
|
||||
window.setAlwaysOnTop(true); //immediately make the change to the window
|
||||
settings.set('user.pinToTop', 'yes');
|
||||
} else {
|
||||
//Checkbox has been unchecked
|
||||
window.setAlwaysOnTop(false);
|
||||
settings.set('user.pinToTop', 'no');
|
||||
}
|
||||
};
|
||||
|
||||
/*******
|
||||
* APP UI
|
||||
********/
|
||||
|
||||
//Window controls
|
||||
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();
|
||||
});
|
||||
|
||||
//Panel tabs
|
||||
var tabLinks = document.querySelectorAll('.tabs button');
|
||||
for (var i = 0; i < tabLinks.length; i++) {
|
||||
tabLinks[i].onclick = function() {
|
||||
var target = this.getAttribute('href').replace('#', '');
|
||||
var sections = document.querySelectorAll('.panel');
|
||||
for(var j=0; j < sections.length; j++) {
|
||||
sections[j].style.display = 'none';
|
||||
}
|
||||
document.getElementById(target).style.display = 'block';
|
||||
for(var k=0; k < tabLinks.length; k++) {
|
||||
tabLinks[k].removeAttribute('class');
|
||||
}
|
||||
this.setAttribute('class', 'active');
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
//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; i<l; ++i)
|
||||
arr[i] = [f(wrap.children[i]), wrap.children[i]];
|
||||
arr.sort(isNum
|
||||
? function(a,b){ return a[0]-b[0]; }
|
||||
: function(a,b){ return a[0]<b[0] ? -1 : a[0]>b[0] ? 1 : 0; }
|
||||
);
|
||||
var par = wrap.parentNode,
|
||||
ref = wrap.nextSibling;
|
||||
par.removeChild(wrap);
|
||||
for(var i=0; i<l; ++i) wrap.appendChild(arr[i][1]);
|
||||
par.insertBefore(wrap, ref);
|
||||
} //sortChildren
|
||||
2
js/offline.min.js
vendored
Normal file
2
js/offline.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
3
main.js
3
main.js
@@ -25,13 +25,14 @@ function createWindow () {
|
||||
// Create the browser window.
|
||||
mainWindow = new electron.BrowserWindow({
|
||||
title: app.getName(),
|
||||
alwaysOnTop: false,
|
||||
//show: false,
|
||||
x: mainWindowState.x,
|
||||
y: mainWindowState.y,
|
||||
width: mainWindowState.width,
|
||||
height: mainWindowState.height,
|
||||
maxWidth: 360,
|
||||
minWidth: 240,
|
||||
minWidth: 280,
|
||||
minHeight: 100,
|
||||
maximizable: false,
|
||||
fullscreenable: false,
|
||||
|
||||
179
package-lock.json
generated
179
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "crypto-price-widget",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -41,6 +41,22 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"aggregate-error": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-1.0.0.tgz",
|
||||
"integrity": "sha1-iINE2tAiCnLjr1CQYRf0h3GSX6w=",
|
||||
"requires": {
|
||||
"clean-stack": "1.3.0",
|
||||
"indent-string": "3.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"indent-string": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz",
|
||||
"integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok="
|
||||
}
|
||||
}
|
||||
},
|
||||
"ajv": {
|
||||
"version": "4.11.8",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz",
|
||||
@@ -1289,6 +1305,11 @@
|
||||
"resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz",
|
||||
"integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A=="
|
||||
},
|
||||
"clean-stack": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-1.3.0.tgz",
|
||||
"integrity": "sha1-noIVAa6XmYbEax1m0tQy2y/UrjE="
|
||||
},
|
||||
"clean-yaml-object": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/clean-yaml-object/-/clean-yaml-object-0.1.0.tgz",
|
||||
@@ -1683,6 +1704,23 @@
|
||||
"resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.0.tgz",
|
||||
"integrity": "sha1-HMPIOkkNZ/ldkeOfatHy4Ia2MEg="
|
||||
},
|
||||
"dns-packet": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.2.2.tgz",
|
||||
"integrity": "sha512-kN+DjfGF7dJGUL7nWRktL9Z18t1rWP3aQlyZdY8XlpvU3Nc6GeFTQApftcjtWKxAZfiggZSGrCEoszNgvnpwDg==",
|
||||
"requires": {
|
||||
"ip": "1.1.5",
|
||||
"safe-buffer": "5.1.1"
|
||||
}
|
||||
},
|
||||
"dns-socket": {
|
||||
"version": "1.6.2",
|
||||
"resolved": "https://registry.npmjs.org/dns-socket/-/dns-socket-1.6.2.tgz",
|
||||
"integrity": "sha512-Ztbaf5fToBfm/4+sVEJi7mT2mJOLYYpI+TpgOhxwp5l28UwunTpHMccVhTe9L0F6pQ2cUF0ja9ukuTCtzYq2Ig==",
|
||||
"requires": {
|
||||
"dns-packet": "1.2.2"
|
||||
}
|
||||
},
|
||||
"doctrine": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz",
|
||||
@@ -1744,6 +1782,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"duplexer3": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
|
||||
"integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI="
|
||||
},
|
||||
"eastasianwidth": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.1.1.tgz",
|
||||
@@ -2629,6 +2672,11 @@
|
||||
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
|
||||
"integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4="
|
||||
},
|
||||
"get-stream": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
|
||||
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
|
||||
},
|
||||
"getpass": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
|
||||
@@ -2936,6 +2984,16 @@
|
||||
"loose-envify": "1.3.1"
|
||||
}
|
||||
},
|
||||
"ip": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
|
||||
"integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo="
|
||||
},
|
||||
"ip-regex": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz",
|
||||
"integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk="
|
||||
},
|
||||
"irregular-plurals": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-1.3.0.tgz",
|
||||
@@ -3045,6 +3103,14 @@
|
||||
"is-extglob": "1.0.0"
|
||||
}
|
||||
},
|
||||
"is-ip": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-ip/-/is-ip-2.0.0.tgz",
|
||||
"integrity": "sha1-aO6gfooKCpTC0IDdZ0xzGrKkYas=",
|
||||
"requires": {
|
||||
"ip-regex": "2.1.0"
|
||||
}
|
||||
},
|
||||
"is-js-type": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-js-type/-/is-js-type-2.0.0.tgz",
|
||||
@@ -3107,6 +3173,47 @@
|
||||
"symbol-observable": "0.2.4"
|
||||
}
|
||||
},
|
||||
"is-online": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-online/-/is-online-7.0.0.tgz",
|
||||
"integrity": "sha1-fiQIwK4efje6jVC9sjcmDTK/2W4=",
|
||||
"requires": {
|
||||
"got": "6.7.1",
|
||||
"p-any": "1.1.0",
|
||||
"p-timeout": "1.2.0",
|
||||
"public-ip": "2.3.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"got": {
|
||||
"version": "6.7.1",
|
||||
"resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz",
|
||||
"integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=",
|
||||
"requires": {
|
||||
"create-error-class": "3.0.2",
|
||||
"duplexer3": "0.1.4",
|
||||
"get-stream": "3.0.0",
|
||||
"is-redirect": "1.0.0",
|
||||
"is-retry-allowed": "1.1.0",
|
||||
"is-stream": "1.1.0",
|
||||
"lowercase-keys": "1.0.0",
|
||||
"safe-buffer": "5.1.1",
|
||||
"timed-out": "4.0.1",
|
||||
"unzip-response": "2.0.1",
|
||||
"url-parse-lax": "1.0.0"
|
||||
}
|
||||
},
|
||||
"timed-out": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz",
|
||||
"integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8="
|
||||
},
|
||||
"unzip-response": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz",
|
||||
"integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c="
|
||||
}
|
||||
}
|
||||
},
|
||||
"is-path-cwd": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz",
|
||||
@@ -3909,6 +4016,19 @@
|
||||
"os-tmpdir": "1.0.2"
|
||||
}
|
||||
},
|
||||
"p-any": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/p-any/-/p-any-1.1.0.tgz",
|
||||
"integrity": "sha512-Ef0tVa4CZ5pTAmKn+Cg3w8ABBXh+hHO1aV8281dKOoUHfX+3tjG2EaFcC+aZyagg9b4EYGsHEjz21DnEE8Og2g==",
|
||||
"requires": {
|
||||
"p-some": "2.0.0"
|
||||
}
|
||||
},
|
||||
"p-finally": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
|
||||
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
|
||||
},
|
||||
"p-limit": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz",
|
||||
@@ -3924,6 +4044,22 @@
|
||||
"p-limit": "1.1.0"
|
||||
}
|
||||
},
|
||||
"p-some": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-some/-/p-some-2.0.0.tgz",
|
||||
"integrity": "sha512-CsRc5gwQNJgSh+pNaGUtgBWBSh9btl8jYLbIdeqLgOLAATZmDDX7xTS5V0mqJk5Dw0gz8FF6s8sAF4D0MvxLhw==",
|
||||
"requires": {
|
||||
"aggregate-error": "1.0.0"
|
||||
}
|
||||
},
|
||||
"p-timeout": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.0.tgz",
|
||||
"integrity": "sha1-mCD5lDTFgXhotPNICe5SkWYNW2w=",
|
||||
"requires": {
|
||||
"p-finally": "1.0.0"
|
||||
}
|
||||
},
|
||||
"package-hash": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/package-hash/-/package-hash-1.2.0.tgz",
|
||||
@@ -4278,6 +4414,47 @@
|
||||
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
|
||||
"integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
|
||||
},
|
||||
"public-ip": {
|
||||
"version": "2.3.5",
|
||||
"resolved": "https://registry.npmjs.org/public-ip/-/public-ip-2.3.5.tgz",
|
||||
"integrity": "sha1-fXhHYliBV2unofpBCwl43yOb33U=",
|
||||
"requires": {
|
||||
"dns-socket": "1.6.2",
|
||||
"got": "6.7.1",
|
||||
"is-ip": "2.0.0",
|
||||
"pify": "2.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"got": {
|
||||
"version": "6.7.1",
|
||||
"resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz",
|
||||
"integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=",
|
||||
"requires": {
|
||||
"create-error-class": "3.0.2",
|
||||
"duplexer3": "0.1.4",
|
||||
"get-stream": "3.0.0",
|
||||
"is-redirect": "1.0.0",
|
||||
"is-retry-allowed": "1.1.0",
|
||||
"is-stream": "1.1.0",
|
||||
"lowercase-keys": "1.0.0",
|
||||
"safe-buffer": "5.1.1",
|
||||
"timed-out": "4.0.1",
|
||||
"unzip-response": "2.0.1",
|
||||
"url-parse-lax": "1.0.0"
|
||||
}
|
||||
},
|
||||
"timed-out": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz",
|
||||
"integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8="
|
||||
},
|
||||
"unzip-response": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz",
|
||||
"integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c="
|
||||
}
|
||||
}
|
||||
},
|
||||
"punycode": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "crypto-price-widget",
|
||||
"productName": "Crypto Price Widget",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.0",
|
||||
"description": "A cross-platform app for tracking Crypto prices",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
||||
BIN
release-builds/Crypto Price Widget-windows-1.1.0.zip
Normal file
BIN
release-builds/Crypto Price Widget-windows-1.1.0.zip
Normal file
Binary file not shown.
@@ -1,4 +1,3 @@
|
||||
// This file is required by the index.html file and will
|
||||
// be executed in the renderer process for that window.
|
||||
// All of the Node.js APIs are available in this process.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user