Reorganisation + Electron fixes (#118)

* Updates package versions

* Updating versions with RCs

* Updated landing page with stock images

* Begins refactoring of websocket
Adds Help component

* Dark theme for charts

* event Event

* Adds cryptocurrency font
Updates wallet to use it

* Rejigs the location of assets

* rxjs update
wallet font correction

* renaming websocket service

* Refactors websocket use
Destroys and subscribes appropriately
Also handles when websocket is not available with intervals

* Fixes issues with electron by rebasing with Maxime GRIS electron builder

* License change

* Readme update

* Parses available and enabled currencies to create an object {Name:X, Enabled:Y}

* Adds methods to convert from string arrays to objects with enabled status for all currencies

* Uses a localstorage cache for config for 15 minutes

* Moves handling of settings to config object

* Fix typescripting

* Fixes issue with saving and loading

* Slows websocket repeats
Adds cool new dictionary style item and iterable.
Updatres currency-list.component to list all enabled currencies and exchanges (still doesn't do anything)

* Updates selected-currency.component to display all currencies ticker updates if there is no selected currency
Will display only selected currency results once it is set
Sets a new property to ensure all currency names are consistent for currency list plans

* Fixes issue where only one component could listen to the websocket at once
Allows you to select a currency in exchange grid mode

* Adds selected currency support to buy & sell components
Updates selected currency ticker to update on change faster

* Adds Online status indicator

* Removal of console.logs for working features

* Allows currency-list.component to aggregate on currency and list exchanges that match it

* Highlights selected currency in currency-list.component
Allows you to select a currency
This commit is contained in:
Scott
2018-05-04 15:07:11 +10:00
committed by Adrian Gallagher
parent 1a473fb59c
commit d882c1dff4
141 changed files with 15572 additions and 7927 deletions

View File

@@ -53,6 +53,10 @@ const routes: Routes = [
{
path: 'currency-list',
component: CurrencyListComponent
},
{
path: 'help',
component: CurrencyListComponent
}
];

View File

@@ -1,58 +1,70 @@
<app-navbar class="navbar mat-elevation-z6"></app-navbar>
<mat-sidenav-container class="container ">
<mat-sidenav #sidenav mode="side" class="sidebar" opened="true">
<mat-nav-list>
<mat-list-item routerLink="dashboard" routerLinkActive="dashboard-highlight">
<mat-icon>view_quilt</mat-icon>&nbsp;
<h3>Dashboard</h3>
</mat-list-item>
<mat-list-item routerLink="wallet" routerLinkActive="wallet-highlight">
<mat-icon>account_balance_wallet</mat-icon>&nbsp;
<h3>Wallet</h3>
</mat-list-item>
<mat-list-item routerLink="trading" routerLinkActive="trading-highlight">
<mat-icon>swap_horiz</mat-icon>&nbsp;
<h3>Trading</h3>
</mat-list-item>
<mat-list-item routerLink="history" routerLinkActive="history-highlight">
<mat-icon>history</mat-icon>&nbsp;
<h3>History</h3>
</mat-list-item>
<mat-list-item routerLink="settings" routerLinkActive="settings-highlight">
<mat-icon>settings</mat-icon>&nbsp;
<h3>Settings</h3>
</mat-list-item>
<mat-list-item routerLink="donate" routerLinkActive="donate-highlight">
<mat-icon>thumb_up</mat-icon>&nbsp;
<h3>Donate</h3>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item>
<mat-icon>grade</mat-icon>&nbsp;
<a href="https://github.com/thrasher-/gocryptotrader" target="_blank">
<h3>GitHub</h3>
</a>
</mat-list-item>
<mat-list-item>
<mat-icon>view_agenda</mat-icon>&nbsp;
<a href="https://trello.com/b/ZAhMhpOy/gocryptotrader" target="_blank">
<h3>Trello</h3>
</a>
</mat-list-item>
<mat-list-item>
<mat-icon>apps</mat-icon>&nbsp;
<a href="https://gocryptotrader.herokuapp.com/" target="_blank">
<h3>Slack</h3>
</a>
</mat-list-item>
<mat-list-item>
<mat-icon>bug_report</mat-icon>&nbsp;
<a href="https://github.com/thrasher-/gocryptotrader/issues/new" target="_blank">
<h3>Report a bug</h3>
</a>
</mat-list-item>
</mat-nav-list>
</mat-sidenav>
<router-outlet class="main"></router-outlet>
</mat-sidenav-container>
<mat-sidenav #sidenav mode="side" class="sidebar" opened="true">
<mat-nav-list>
<mat-list-item routerLink="dashboard" routerLinkActive="dashboard-highlight">
<mat-icon>view_quilt</mat-icon>&nbsp;
<h3>Dashboard</h3>
</mat-list-item>
<mat-list-item routerLink="wallet" routerLinkActive="wallet-highlight">
<mat-icon>account_balance_wallet</mat-icon>&nbsp;
<h3>Wallet</h3>
</mat-list-item>
<mat-list-item routerLink="trading" routerLinkActive="trading-highlight">
<mat-icon>swap_horiz</mat-icon>&nbsp;
<h3>Trading</h3>
</mat-list-item>
<mat-list-item routerLink="history" routerLinkActive="history-highlight">
<mat-icon>history</mat-icon>&nbsp;
<h3>History</h3>
</mat-list-item>
<mat-list-item routerLink="settings" routerLinkActive="settings-highlight">
<mat-icon>settings</mat-icon>&nbsp;
<h3>Settings</h3>
</mat-list-item>
<mat-list-item routerLink="help_outline" routerLinkActive="help-highlight">
<mat-icon>help</mat-icon>&nbsp;
<h3>Help</h3>
</mat-list-item>
<mat-list-item routerLink="donate" routerLinkActive="donate-highlight">
<mat-icon>thumb_up</mat-icon>&nbsp;
<h3>Donate</h3>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item>
<mat-icon>grade</mat-icon>&nbsp;
<a href="https://github.com/thrasher-/gocryptotrader" target="_blank">
<h3>GitHub</h3>
</a>
</mat-list-item>
<mat-list-item>
<mat-icon>view_agenda</mat-icon>&nbsp;
<a href="https://trello.com/b/ZAhMhpOy/gocryptotrader" target="_blank">
<h3>Trello</h3>
</a>
</mat-list-item>
<mat-list-item>
<mat-icon>apps</mat-icon>&nbsp;
<a href="https://gocryptotrader.herokuapp.com/" target="_blank">
<h3>Slack</h3>
</a>
</mat-list-item>
<mat-list-item>
<mat-icon>bug_report</mat-icon>&nbsp;
<a href="https://github.com/thrasher-/gocryptotrader/issues/new" target="_blank">
<h3>Report a bug</h3>
</a>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item *ngIf="isConnected" matTooltip="Online!">
<mat-icon>network_wifi</mat-icon>&nbsp;
</mat-list-item>
<mat-list-item *ngIf="!isConnected" matTooltip="Offline">
<mat-icon>signal_wifi_off</mat-icon>&nbsp;
</mat-list-item>
</mat-nav-list>
</mat-sidenav>
<router-outlet class="main"></router-outlet>
</mat-sidenav-container>

View File

@@ -41,6 +41,10 @@
color: blueviolet !important;
}
.help-highlight {
color: red !important;
}
.settings-highlight {
color: magenta !important;
}

View File

@@ -3,6 +3,7 @@ import { ElectronService } from './providers/electron.service';
import { MatSidenav } from '@angular/material';
import { SidebarService } from './services/sidebar/sidebar.service';
import { Router, NavigationEnd } from '@angular/router';
import {WebsocketResponseHandlerService }from './services/websocket-response-handler/websocket-response-handler.service';
@Component({
selector: 'app-root',
@@ -11,10 +12,12 @@ import { Router, NavigationEnd } from '@angular/router';
})
export class AppComponent {
sidebarService: SidebarService
public currentUrl:string;
public currentUrl: string;
@ViewChild('sidenav') public sidenav: MatSidenav;
private ws : WebsocketResponseHandlerService;
public isConnected :boolean = false;
constructor(public electronService: ElectronService,something: SidebarService, private router:Router) {
constructor(public electronService: ElectronService, sidebarService: SidebarService, private router: Router, private websocketHandler: WebsocketResponseHandlerService) {
if (electronService.isElectron()) {
console.log('Mode electron');
@@ -26,18 +29,26 @@ export class AppComponent {
console.log('Mode web');
}
this.sidebarService = something;
router.events.subscribe(event => {
this.isConnected = this.websocketHandler.isConnected;
this.sidebarService = sidebarService;
router.events.subscribe(event => {
if (event instanceof NavigationEnd ) {
console.log("current url",event.url); // event.url has current url
this.currentUrl = event.url;
}
});
if (event instanceof NavigationEnd) {
this.isConnected = this.websocketHandler.isConnected;
console.log("current url", event.url); // event.url has current url
this.currentUrl = event.url;
}
});
var interval = setInterval(() => {
this.isConnected = this.websocketHandler.isConnected;
}, 2000);
}
ngOnInit() {
this.sidebarService.setSidenav(this.sidenav);
}
//This will be replaced with a log in prompt which will then add the credentials to session storage
window.sessionStorage["username"] = "admin";
window.sessionStorage["password"] = "e7cf3ef4f17c3999a94f2c6f612e8a888e5b1026878e4e19398b23bd38ec221a";
}
}

23
web/src/app/app.config.ts Normal file
View File

@@ -0,0 +1,23 @@
import { CONF_LOCAL } from '../environments/environment.local';
import { CONF_DEV } from '../environments/environment.dev';
import { CONF_PROD } from '../environments/environment.prod';
const ENV = 'local';
const LOCAL: String = 'local';
const DEV: String = 'dev';
const PROD: String = 'prod';
let conf: any;
console.log('Env', ENV);
if (ENV === PROD) {
conf = CONF_PROD;
} else if (ENV === DEV) {
conf = CONF_DEV;
} else {
conf = CONF_LOCAL;
}
export const AppConfig = Object.assign({}, conf);

View File

@@ -42,9 +42,10 @@ import { DonateComponent } from './pages/donate/donate.component';
import { NavbarComponent } from './shared/navbar/navbar.component';
import { AllEnabledCurrencyTickersComponent } from './shared/all-updates-ticker/all-updates-ticker.component';
import { ThemePickerComponent } from './shared/theme-picker/theme-picker';
import {IterateMapPipe, EnabledCurrenciesPipe} from './shared/classes/pipes';
//services
import { WebsocketService } from './services/websocket/websocket.service';
import { WebsocketHandlerService } from './services/websocket-handler/websocket-handler.service';
import { WebsocketResponseHandlerService } from './services/websocket-response-handler/websocket-response-handler.service';
import { SidebarService } from './services/sidebar/sidebar.service';
import { ElectronService } from './providers/electron.service';
import { StyleManagerService } from './services/style-manager/style-manager.service';
@@ -69,6 +70,7 @@ import { BuyFormComponent } from './shared/buy-form/buy-form.component';
import { ExchangeGridComponent } from './pages/exchange-grid/exchange-grid.component';
import { CurrencyListComponent } from './pages/currency-list/currency-list.component';
import { SellFormComponent } from './shared/sell-form/sell-form.component';
import { HelpComponent } from './pages/help/help.component';
@NgModule({
@@ -95,6 +97,9 @@ import { SellFormComponent } from './shared/sell-form/sell-form.component';
ExchangeGridComponent,
CurrencyListComponent,
SellFormComponent,
HelpComponent,
IterateMapPipe,
EnabledCurrenciesPipe
],
imports: [
BrowserModule,
@@ -124,7 +129,7 @@ import { SellFormComponent } from './shared/sell-form/sell-form.component';
providers: [
ElectronService,
WebsocketService,
WebsocketHandlerService,
WebsocketResponseHandlerService,
SidebarService,
StyleManagerService,
ThemeStorageService,

View File

@@ -1,35 +1,23 @@
<mat-list>
<h3 matSubheader>Poloniex</h3>
<mat-list-item >
<mat-icon matListIcon>attach_money</mat-icon>
<h4 matLine>BTC_USD</h4>
<button mat-button>SELECT</button>
</mat-list-item>
<mat-list-item >
<mat-icon matListIcon>attach_money</mat-icon>
<h4 matLine>LTC_USD</h4>
<button mat-button>SELECT</button>
</mat-list-item>
<mat-list-item >
<mat-icon matListIcon>attach_money</mat-icon>
<h4 matLine>ETH_USD</h4>
<button mat-button>SELECT</button>
</mat-list-item>
<mat-divider></mat-divider>
<h3 matSubheader>Kraken</h3>
<mat-list-item >
<mat-icon matListIcon>attach_money</mat-icon>
<h4 matLine>BTC_USD</h4>
<button mat-button>SELECT</button>
</mat-list-item>
<mat-list-item >
<mat-icon matListIcon>attach_money</mat-icon>
<h4 matLine>LTC_USD</h4>
<button mat-button>SELECT</button>
</mat-list-item>
<mat-list-item >
<mat-icon matListIcon>attach_money</mat-icon>
<h4 matLine>ETH_USD</h4>
<button mat-button>SELECT</button>
</mat-list-item>
</mat-list>
<mat-accordion>
<mat-expansion-panel *ngFor="let currency of exchangeCurrencies | iterateMap">
<mat-expansion-panel-header [ngClass]="{'selected' : selectedCurrency == currency.value}" >
<mat-panel-title>
{{currency.value}}
</mat-panel-title>
<mat-panel-description>
</mat-panel-description>
</mat-expansion-panel-header>
image and blurb
<div>
<i>Only displaying enabled currencies</i>
</div>
<form class="form-content">
<mat-list>
<mat-list-item [ngClass]="{'selected' : selectedExchange == exchange}" *ngFor="let exchange of currency.key" >
<h4 matLine>{{exchange}}</h4>
<button mat-button (click)="selectCurrency(exchange, currency.value)">SELECT</button>
</mat-list-item>
</mat-list>
</form>
</mat-expansion-panel>
</mat-accordion>

View File

@@ -6,4 +6,8 @@
}
.ETH {
color:darkslategrey;
}
.selected, .selected:hover, .selected:focus, .selected::selection {
background: rgba(100,250,100,0.2);
}

View File

@@ -1,15 +1,73 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, OnDestroy, Pipe, PipeTransform} from '@angular/core';
import { WebsocketResponseHandlerService} from './../../services/websocket-response-handler/websocket-response-handler.service';
import { WebSocketMessageType, WebSocketMessage} from './../../shared/classes/websocket';
import { Config, CurrencyPairRedux} from './../../shared/classes/config';
import { EnabledCurrenciesPipe, IterateMapPipe} from './../../shared/classes/pipes';
@Component({
selector: 'app-currency-list',
templateUrl: './currency-list.component.html',
styleUrls: ['./currency-list.component.scss']
styleUrls: ['./currency-list.component.scss'],
})
export class CurrencyListComponent implements OnInit {
public settings: Config = new Config();
private ws: WebsocketResponseHandlerService;
public selectedCurrency :string;
public selectedExchange :string;
public exchangeCurrencies: Map <string, string[] > = new Map < string, string[] > ();
constructor() { }
constructor(private websocketHandler: WebsocketResponseHandlerService) {
this.selectedExchange = window.localStorage["selectedExchange"];
this.selectedCurrency = window.localStorage["selectedCurrency"];
this.ws = websocketHandler;
this.ws.shared.subscribe(msg => {
if (msg.event === WebSocketMessageType.GetConfig) {
this.settings.setConfig(msg.data);
this.getExchangeCurrencies();
}
});
}
ngOnInit() {
this.getSettings();
}
public selectCurrency(exchange:string,currency:string) {
window.localStorage["selectedExchange"] = exchange;
window.localStorage["selectedCurrency"] = currency;
this.selectedExchange = window.localStorage["selectedExchange"];
this.selectedCurrency = window.localStorage["selectedCurrency"];
}
public getExchangeCurrencies(): void {
for (var i = 0; i < this.settings.Exchanges.length; i++) {
if (this.settings.Exchanges[i].Enabled === true) {
for (var j = 0; j < this.settings.Exchanges[i].Pairs.length; j++) {
if(this.settings.Exchanges[i].Pairs[j].Enabled) {
if(this.exchangeCurrencies.has(this.settings.Exchanges[i].Pairs[j].ParsedName)) {
var array = this.exchangeCurrencies.get(this.settings.Exchanges[i].Pairs[j].ParsedName);
array.push(this.settings.Exchanges[i].Name);
this.exchangeCurrencies.set(this.settings.Exchanges[i].Pairs[j].ParsedName, array);
} else {
var exchangeArray = new Array<string>();
exchangeArray.push(this.settings.Exchanges[i].Name);
this.exchangeCurrencies.set(this.settings.Exchanges[i].Pairs[j].ParsedName, exchangeArray);
}
}
}
}
}
this.exchangeCurrencies.forEach((value: string[], key: string) => {});
}
private getSettings(): void {
if (this.settings.isConfigCacheValid()) {
this.settings.setConfig(JSON.parse(window.localStorage['config']))
this.getExchangeCurrencies();
} else {
this.ws.messages.next(WebSocketMessage.GetSettingsMessage());
}
}
}

View File

@@ -40,7 +40,7 @@ mat-card-footer button {
position: fixed;
top: auto;
right: 5rem;
bottom: 3rem;
bottom: 5rem;
left: auto;
z-index: 2;
display: flex;
@@ -49,7 +49,7 @@ mat-card-footer button {
.buy-sell-card {
width: 20rem;
height: 22rem;
height: 24rem;
margin-left: auto;
margin-right: 1rem;
z-index: 3;

View File

@@ -1,17 +1,17 @@
<mat-card class="full-card">
<mat-card class="full-card">
<mat-card-header>
<mat-card-title>Donations</mat-card-title>
<mat-card-subtitle>We give our thanks</mat-card-subtitle>
</mat-card-header>
<mat-card-content>
<img class="heart" src="/assets/early-dumb-donate.png"/>
<p>If this framework helped you in any way, or you would like to support the developers working on it, please donate</p>
<mat-list>
<mat-list-item >
<mat-icon mat-list-icon class="BTC">attach_money</mat-icon>
<h4 mat-line>Address:</h4>
<h4 mat-line>1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB</h4>
</mat-list-item>
</mat-list>
<img class="heart" src="./assets/images/donate.png" />
<p>If this framework helped you in any way, or you would like to support the developers working on it, please donate</p>
<mat-list>
<mat-list-item>
<mat-icon mat-list-icon class="BTC">attach_money</mat-icon>
<h4 mat-line>Address:</h4>
<h4 mat-line>1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB</h4>
</mat-list-item>
</mat-list>
</mat-card-content>
</mat-card>

View File

@@ -1,59 +1,22 @@
<mat-accordion>
<mat-expansion-panel >
<mat-expansion-panel-header>
<mat-expansion-panel *ngFor="let exchange of exchangeCurrencies | iterateMap">
<mat-expansion-panel-header [ngClass]="{'selected' : selectedExchange == exchange.value}">
<mat-panel-title>
Poloniex
{{exchange.value}}
</mat-panel-title>
<mat-panel-description>
</mat-panel-description>
</mat-expansion-panel-header>
image and blurb
<div>
<i>Only displaying enabled currencies</i>
</div>
<form class="form-content">
<mat-list>
<mat-list-item >
<mat-icon matListIcon>attach_money</mat-icon>
<h4 matLine>BTC_USD</h4>
<button mat-button>SELECT</button>
<mat-list-item [ngClass]="{'selected' : selectedCurrency == currency.ParsedName}" *ngFor="let currency of exchange.key | enabledCurrencies" >
<h4 matLine>{{currency.ParsedName}}</h4>
<button mat-button (click)="selectCurrency(exchange.value,currency.ParsedName)">SELECT</button>
</mat-list-item>
<mat-list-item >
<mat-icon matListIcon>attach_money</mat-icon>
<h4 matLine>LTC_USD</h4>
<button mat-button>SELECT</button>
</mat-list-item>
<mat-list-item >
<mat-icon matListIcon>attach_money</mat-icon>
<h4 matLine>ETH_USD</h4>
<button mat-button>SELECT</button>
</mat-list-item>
</mat-list>
</form>
</mat-expansion-panel><mat-expansion-panel >
<mat-expansion-panel-header>
<mat-panel-title>
Kraken
</mat-panel-title>
<mat-panel-description>
</mat-panel-description>
</mat-expansion-panel-header>
image and blurb
<form class="form-content">
<mat-list>
<mat-list-item >
<mat-icon matListIcon>attach_money</mat-icon>
<h4 matLine>BTC_USD</h4>
<button mat-button>SELECT</button>
</mat-list-item>
<mat-list-item >
<mat-icon matListIcon>attach_money</mat-icon>
<h4 matLine>LTC_USD</h4>
<button mat-button>SELECT</button>
</mat-list-item>
<mat-list-item >
<mat-icon matListIcon>attach_money</mat-icon>
<h4 matLine>ETH_USD</h4>
<button mat-button>SELECT</button>
</mat-list-item>
</mat-list>
</form>
</mat-expansion-panel>

View File

@@ -0,0 +1,3 @@
.selected, .selected:hover, .selected:focus, .selected::selection {
background: rgba(100,250,100,0.2);
}

View File

@@ -1,4 +1,8 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, OnDestroy, Pipe, PipeTransform} from '@angular/core';
import { WebsocketResponseHandlerService} from './../../services/websocket-response-handler/websocket-response-handler.service';
import { WebSocketMessageType, WebSocketMessage} from './../../shared/classes/websocket';
import { Config, CurrencyPairRedux} from './../../shared/classes/config';
import { EnabledCurrenciesPipe, IterateMapPipe} from './../../shared/classes/pipes';
@Component({
selector: 'app-exchange-grid',
@@ -6,10 +10,54 @@ import { Component, OnInit } from '@angular/core';
styleUrls: ['./exchange-grid.component.scss']
})
export class ExchangeGridComponent implements OnInit {
public settings: Config = new Config();
private ws: WebsocketResponseHandlerService;
public selectedCurrency :string;
public selectedExchange :string;
public exchangeCurrencies: Map < string, CurrencyPairRedux[] > = new Map < string, CurrencyPairRedux[] > ();
constructor() { }
ngOnInit() {
constructor(private websocketHandler: WebsocketResponseHandlerService) {
this.selectedExchange = window.localStorage["selectedExchange"];
this.selectedCurrency = window.localStorage["selectedCurrency"];
this.ws = websocketHandler;
this.ws.shared.subscribe(msg => {
if (msg.event === WebSocketMessageType.GetConfig) {
this.settings.setConfig(msg.data);
this.getExchangeCurrencies();
}
});
}
ngOnInit() {
this.getSettings();
}
public selectCurrency(exchange:string,currency:string) {
window.localStorage["selectedExchange"] = exchange;
window.localStorage["selectedCurrency"] = currency;
this.selectedExchange = window.localStorage["selectedExchange"];
this.selectedCurrency = window.localStorage["selectedCurrency"];
}
public getExchangeCurrencies(): void {
for (var i = 0; i < this.settings.Exchanges.length; i++) {
if (this.settings.Exchanges[i].Enabled === true) {
this.exchangeCurrencies.set(this.settings.Exchanges[i].Name, this.settings.Exchanges[i].Pairs)
}
}
this.exchangeCurrencies.forEach((value: CurrencyPairRedux[], key: string) => {});
}
private getSettings(): void {
if (this.settings.isConfigCacheValid()) {
this.settings.setConfig(JSON.parse(window.localStorage['config']))
this.getExchangeCurrencies();
} else {
this.ws.messages.next(WebSocketMessage.GetSettingsMessage());
}
}
}

View File

@@ -0,0 +1,3 @@
<p>
help works!
</p>

View File

@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { HelpComponent } from './help.component';
describe('HelpComponent', () => {
let component: HelpComponent;
let fixture: ComponentFixture<HelpComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ HelpComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(HelpComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,15 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-help',
templateUrl: './help.component.html',
styleUrls: ['./help.component.scss']
})
export class HelpComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}

View File

@@ -1,5 +1,56 @@
<div class="docs-homepage-promo">
<h2 class="mat-h1">Welcome to GoCryptoTrader</h2>
<h1 class="mat-h1">Welcome to GoCryptoTrader</h1>
<p>GoCryptoTrader is a multi-currency, multi-exchange trader for cryptocurrencies</p>
<p>It is under active development and you can see its development progress by clicking the trello button to the left</p>
<p>If you like what you see, consider clicking the donation button to the left</p>
<div class="docs-homepage-row">
<div class="docs-homepage-promo-img">
<img src="./assets/exchanges.jpg" />
</div>
<div class="docs-homepage-promo-desc">
<h2>Multi-currency, multi-exchange</h2>
<p>With support for over 25 of the top cryptocurrency exchanges</p>
<div class="docs-homepage-bottom-start">
<a mat-raised-button class="docs-button" routerLink="dashboard">Get started</a>
</div>
</div>
</div>
<div class="docs-homepage-row docs-homepage-reverse-row">
<div class="docs-homepage-promo-img">
<img src="./assets/loop.png" />
</div>
<div class="docs-homepage-promo-desc">
<h2>High speed, low drag</h2>
<p>Constant checking of all enabled exchanges* to get you the most up to date information</p>
<div class="docs-homepage-bottom-start">
<a mat-raised-button class="docs-button" routerLink="dashboard">Get started</a>
</div>
</div>
</div>
<div class="docs-homepage-row">
<div class="docs-homepage-promo-img">
<img src="./assets/centralised.png" />
</div>
<div class="docs-homepage-promo-desc">
<h2>Centralised management</h2>
<p>Add and manage all your wallets from one application</p>
<div class="docs-homepage-bottom-start">
<a mat-raised-button class="docs-button" routerLink="dashboard">Get started</a>
</div>
</div>
</div>
<div class="docs-homepage-row docs-homepage-reverse-row">
<div class="docs-homepage-promo-img">
<img src="./assets/material.png" />
</div>
<div class="docs-homepage-promo-desc">
<h2>Optimized for Angular</h2>
<p>The latest tech with Material design lets you focus on what's important</p>
<div class="docs-homepage-bottom-start">
<a mat-raised-button class="docs-button" routerLink="dashboard">Get started</a>
</div>
</div>
</div>
<div class="docs-homepage-bottom-start">
<a mat-raised-button class="docs-button" routerLink="dashboard">Get started</a>
</div>
</div>

View File

@@ -1,3 +1,71 @@
.example-card {
width: 400px;
}
.docs-homepage-promo {
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
padding: 16px;
}
.docs-homepage-promo h2 {
font-size: 25px;
font-weight: 400;
margin: 0 0 16px 0;
padding: 0;
}
.docs-homepage-promo p {
font-size: 16px;
font-weight: 400;
line-height: 28px;
margin: 0 0 24px 0;
padding: 0;
}
.docs-homepage-promo-img img {
max-width: 90%;
max-height: 300px;
}
.docs-homepage-promo-desc {
line-height: 2;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
}
.docs-homepage-promo-desc,
.docs-homepage-promo-img {
width: 50%;
}
.docs-homepage-promo-img {
text-align: center;
}
.docs-homepage-row {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
width: 50%;
margin: 60px 0;
}
.docs-homepage-reverse-row {
-webkit-box-orient: horizontal;
-webkit-box-direction: reverse;
-ms-flex-direction: row-reverse;
flex-direction: row-reverse;
}

View File

@@ -7,7 +7,7 @@
<mat-accordion>
<mat-expansion-panel *ngIf="settings.SMSGlobal != null">
<mat-expansion-panel-header >
<mat-expansion-panel-header>
<mat-panel-title>
SMS Global
</mat-panel-title>
@@ -15,7 +15,7 @@
SMS configuration and contact management
<mat-icon>phone_iphone</mat-icon>
</mat-panel-description>
</mat-expansion-panel-header>
</mat-expansion-panel-header>
<form class="form-content">
<mat-checkbox name="smsEnabled" [(ngModel)]="settings.SMSGlobal.Enabled">Enabled</mat-checkbox>
<div mat-line></div>
@@ -53,25 +53,23 @@
<form class="form-content">
<mat-checkbox name="exchangeEnabled" [(ngModel)]="exchange.Enabled">Enabled</mat-checkbox>
<div mat-line></div>
<mat-form-field>
<input matInput name="apiKey" [(ngModel)]="exchange.APIKey" [disabled]="!exchange.Enabled" placeholder="API Key*">
</mat-form-field>
<mat-form-field>
<input matInput name="apiSecretKey" [(ngModel)]="exchange.APISecret" [disabled]="!exchange.Enabled" placeholder="API Secret Key*">
</mat-form-field>
<mat-form-field>
<input matInput name="apiClientId" [(ngModel)]="exchange.ClientID" [disabled]="!exchange.Enabled" placeholder="API ClientID">
</mat-form-field>
<div mat-line></div>
<mat-panel-description>
Enabled Currency pairs {{enabledCurrencies.selectedOptions.selected.length}} - Managed via config temporarily
</mat-panel-description>
<div mat-line></div>
<mat-selection-list #enabledCurrencies>
<mat-list-option [disabled]="!exchange.Enabled || true" *ngFor="let currency of exchange.AvailablePairs.split(',')">
{{currency}}
</mat-list-option>
</mat-selection-list>
<mat-form-field>
<input matInput name="apiKey" [(ngModel)]="exchange.APIKey" [disabled]="!exchange.Enabled" placeholder="API Key*">
</mat-form-field>
<mat-form-field>
<input matInput name="apiSecretKey" [(ngModel)]="exchange.APISecret" [disabled]="!exchange.Enabled" placeholder="API Secret Key*">
</mat-form-field>
<mat-form-field>
<input matInput name="apiClientId" [(ngModel)]="exchange.ClientID" [disabled]="!exchange.Enabled" placeholder="API ClientID">
</mat-form-field>
<div mat-line></div>
<h4>
Enabled currencies
</h4>
<div *ngFor="let currency of exchange.Pairs">
<p>{{currency.Name}}</p>
<mat-checkbox name="{{currency.Name}}2" [(ngModel)]="currency.Enabled"></mat-checkbox>
</div>
</form>
</mat-expansion-panel>
</mat-accordion>

View File

@@ -1,145 +1,50 @@
import { Component, OnInit } from '@angular/core';
import { WebsocketHandlerService } from './../../services/websocket-handler/websocket-handler.service';
import { Component, OnInit, OnDestroy } from '@angular/core';
import { WebsocketResponseHandlerService } from './../../services/websocket-response-handler/websocket-response-handler.service';
import { WebSocketMessageType, WebSocketMessage } from './../../shared/classes/websocket';
import { Config, CurrencyPairRedux } from './../../shared/classes/config';
@Component({
selector: 'app-settings',
templateUrl: './settings.component.html',
styleUrls: ['./settings.component.scss']
styleUrls: ['./settings.component.scss'],
})
export class SettingsComponent implements OnInit {
public settings: Config = null;
private ws: WebsocketHandlerService;
private failCount = 0;
private timer: any;
public settings: Config = new Config();
private ws: WebsocketResponseHandlerService;
private getSettingsMessage = {
Event: 'GetConfig',
data: null,
};
constructor(private websocketHandler: WebsocketHandlerService) {
constructor(private websocketHandler: WebsocketResponseHandlerService) {
this.ws = websocketHandler;
this.ws.messages.subscribe(msg => {
if (msg.Event === 'GetConfig') {
this.settings = <Config>msg.data;
} else if (msg.Event === 'SaveConfig') {
// something!
}
});
}
ngOnInit() {
this.ws.shared.subscribe(msg => {
if (msg.event === WebSocketMessageType.GetConfig) {
this.settings.setConfig(msg.data);
} else if (msg.event === WebSocketMessageType.SaveConfig) {
// check if err is returned, then display some notification
}
});
this.getSettings();
}
private getSettings(): void {
this.ws.messages.next(this.getSettingsMessage);
this.resendMessageIfPageRefreshed();
if(this.settings.isConfigCacheValid()) {
this.settings.setConfig(JSON.parse(window.localStorage['config']))
} else {
this.ws.messages.next(WebSocketMessage.GetSettingsMessage());
}
}
private saveSettings(): void {
//Send the message
this.settings.fromReduxToArray()
var settingsSave = {
Event: 'SaveConfig',
data: this.settings,
}
this.ws.messages.next(settingsSave);
}
//there has to be a better way
private resendMessageIfPageRefreshed(): void {
if (this.failCount <= 10) {
setTimeout(() => {
if (this.settings === null) {
//console.log(this.failCount);
//console.log('Settings hasnt been set. Trying again');
this.failCount++;
this.getSettings();
}
}, 1000);
} else {
// something has gone wrong
console.log('Could not load settings. Check if GocryptoTrader server is running, otherwise open a ticket');
}
}
}
export interface CurrencyPairFormat {
Uppercase: boolean;
Delimiter: string;
}
export interface PortfolioAddresses {
Addresses?: any;
}
export interface Contact {
Name: string;
Number: string;
Enabled: boolean;
}
export interface SMSGlobal {
Enabled: boolean;
Username: string;
Password: string;
Contacts: Contact[];
}
export interface Webserver {
Enabled: boolean;
AdminUsername: string;
AdminPassword: string;
ListenAddress: string;
WebsocketConnectionLimit: number;
WebsocketAllowInsecureOrigin: boolean;
}
export interface ConfigCurrencyPairFormat {
Uppercase: boolean;
Index: string;
Delimiter: string;
}
export interface RequestCurrencyPairFormat {
Uppercase: boolean;
Index: string;
Delimiter: string;
Separator: string;
}
export interface Exchange {
Name: string;
Enabled: boolean;
Verbose: boolean;
Websocket: boolean;
RESTPollingDelay: number;
AuthenticatedAPISupport: boolean;
APIKey: string;
APISecret: string;
AvailablePairs: string;
EnabledPairs: string;
BaseCurrencies: string;
AssetTypes: string;
ConfigCurrencyPairFormat: ConfigCurrencyPairFormat;
RequestCurrencyPairFormat: RequestCurrencyPairFormat;
ClientID: string;
}
export interface Config {
Name: string;
EncryptConfig?: number;
Cryptocurrencies: string;
CurrencyExchangeProvider: string;
CurrencyPairFormat: CurrencyPairFormat;
PortfolioAddresses: PortfolioAddresses;
SMSGlobal: SMSGlobal;
Webserver: Webserver;
Exchanges: Exchange[];
}

View File

@@ -11,7 +11,7 @@
<mat-list>
<mat-list-item *ngFor="let coin of wallet?.coin_totals">
<mat-icon mat-list-icon [ngClass]="coin.coin">{{coin.icon}}</mat-icon>
<i [ngClass]="coin.icon"></i>
<h4 mat-line>{{coin.coin}}</h4>
<h4 mat-line>{{coin.balance}}</h4>
</mat-list-item>
@@ -26,21 +26,21 @@
</mat-expansion-panel-header>
<mat-list>
<mat-list-item *ngFor="let coin of wallet?.online_summary.BTC">
<mat-icon mat-list-icon class="BTC">{{coinIcon('BTC')}}</mat-icon>
<i class="cc btc"></i>
<h4 mat-line>Address: {{coin.address}}</h4>
<h4 mat-line>{{coin.balance}}{{coin.coin}} - {{coin.percentage}}%</h4>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item *ngFor="let coin of wallet?.online_summary.LTC">
<mat-icon mat-list-icon class="LTC">{{coinIcon('LTC')}}</mat-icon>
<i class="cc ltc"></i>
<h4 mat-line>Address: {{coin.address}}</h4>
<h4 mat-line>{{coin.balance}}{{coin.coin}} - {{coin.percentage}}%</h4>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item *ngFor="let coin of wallet?.online_summary.ETH">
<mat-icon mat-list-icon class="ETH">{{coinIcon('ETH')}}</mat-icon>
<i class="cc eth"></i>
<h4 mat-line>Address: {{coin.address}}</h4>
<h4 mat-line>{{coin.balance}}{{coin.coin}} - {{coin.percentage}}%</h4>
</mat-list-item>
@@ -55,21 +55,21 @@
</mat-expansion-panel-header>
<mat-list>
<mat-list-item *ngFor="let coin of wallet?.offline_summary.BTC">
<mat-icon mat-list-icon class="BTC">{{coinIcon('BTC')}}</mat-icon>
<i class="cc btc"></i>
<h4 mat-line>Address: {{coin.address}}</h4>
<h4 mat-line>{{coin.balance}}{{coin.coin}} - {{coin.percentage}}%</h4>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item *ngFor="let coin of wallet?.offline_summary.LTC">
<mat-icon mat-list-icon class="LTC">{{coinIcon('LTC')}}</mat-icon>
<i class="cc ltc"></i>
<h4 mat-line>Address: {{coin.address}}</h4>
<h4 mat-line>{{coin.balance}}{{coin.coin}} - {{coin.percentage}}%</h4>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item *ngFor="let coin of wallet?.offline_summary.ETH">
<mat-icon mat-list-icon class="ETH">{{coinIcon('ETH')}}</mat-icon>
<i class="cc eth"></i>
<h4 mat-line>Address: {{coin.address}}</h4>
<h4 mat-line>{{coin.balance}}{{coin.coin}} - {{coin.percentage}}%</h4>
</mat-list-item>
@@ -85,7 +85,7 @@
<mat-list>
<mat-list-item *ngFor="let coin of wallet?.coins_online">
<mat-icon mat-list-icon [ngClass]="coin.coin">{{coin.icon}}</mat-icon>
<i [ngClass]="coin.icon"></i>
<h4 mat-line>{{coin.coin}}</h4>
<h4 mat-line>{{coin.balance}}</h4>
</mat-list-item>
@@ -101,7 +101,7 @@
<mat-list>
<mat-list-item *ngFor="let coin of wallet?.coins_offline">
<mat-icon mat-list-icon [ngClass]="coin.coin">{{coin.icon}}</mat-icon>
<i [ngClass]="coin.icon"></i>
<h4 mat-line>{{coin.coin}}</h4>
<h4 mat-line>{{coin.balance}}</h4>
</mat-list-item>

View File

@@ -1,34 +1,33 @@
import { Component, OnInit } from '@angular/core';
import { WebsocketHandlerService } from './../../services/websocket-handler/websocket-handler.service';
import { Component, OnInit, OnDestroy } from '@angular/core';
import { WebsocketResponseHandlerService } from './../../services/websocket-response-handler/websocket-response-handler.service';
import { Wallet, CoinTotal } from './../../shared/classes/wallet';
import {Sort} from '@angular/material';
import { Sort } from '@angular/material';
import { WebSocketMessageType, WebSocketMessage } from './../../shared/classes/websocket';
@Component({
selector: 'app-wallet',
templateUrl: './wallet.component.html',
styleUrls: ['./wallet.component.scss']
styleUrls: ['./wallet.component.scss'],
})
export class WalletComponent implements OnInit {
private ws: WebsocketHandlerService;
private ws: WebsocketResponseHandlerService;
private failCount = 0;
private timer: any;
public wallet: Wallet;
displayedColumns = ['coin', 'balance'];
private getWalletMessage = {
Event: 'GetPortfolio',
event: 'GetPortfolio',
data: null,
};
constructor(private websocketHandler: WebsocketHandlerService) {
constructor(private websocketHandler: WebsocketResponseHandlerService) {
this.wallet= null;
this.ws = websocketHandler;
this.ws.messages.subscribe(msg => {
if (msg.Event === 'GetPortfolio') {
console.log(JSON.stringify(msg.data));
this.ws.shared.subscribe(msg => {
if (msg.event === WebSocketMessageType.GetPortfolio) {
this.wallet = <Wallet>msg.data;
this.attachIcon(this.wallet.coin_totals);
this.attachIcon(this.wallet.coins_offline);
this.attachIcon(this.wallet.coins_online);
@@ -44,11 +43,19 @@ export class WalletComponent implements OnInit {
});
}
ngOnInit() {
this.setWallet();
}
private setWallet():void {
this.ws.messages.next(this.getWalletMessage);
}
public coinIcon(coin:string) :string {
switch(coin) {
case "BTC": return "attach_money";
case "LTC": return "attach_money";
case "ETH": return "attach_money";
case "BTC": return "cc BTC";
case "LTC": return "cc LTC";
case "ETH": return "cc ETH";
}
}
@@ -60,28 +67,5 @@ export class WalletComponent implements OnInit {
}
}
ngOnInit() {
this.setWallet();
}
//there has to be a better way
private resendMessageIfPageRefreshed(): void {
if (this.failCount <= 10) {
setTimeout(() => {
if (this.wallet === null || this.wallet === undefined) {
this.failCount++;
this.setWallet();
}
}, 1000);
} else {
console.log('Could not load wallet. Check if GocryptoTrader server is running, otherwise open a ticket');
}
}
private setWallet():void {
this.ws.messages.next(this.getWalletMessage);
this.resendMessageIfPageRefreshed();
}
}

View File

@@ -1,15 +0,0 @@
import { TestBed, inject } from '@angular/core/testing';
import { WebsocketHandlerService } from './websocket-handler.service';
describe('WebsocketHandlerService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [WebsocketHandlerService]
});
});
it('should be created', inject([WebsocketHandlerService], (service: WebsocketHandlerService) => {
expect(service).toBeTruthy();
}));
});

View File

@@ -1,44 +0,0 @@
import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs/Rx';
import { WebsocketService } from './../../services/websocket/websocket.service';
const WEBSOCKET_URL = 'ws://localhost:9050/ws';
export interface Message {
Event: string,
data:any,
Exchange:string,
AssetType:string
}
@Injectable()
export class WebsocketHandlerService {
public messages: Subject<any>;
private authenticateMessage = {
Event:'auth',
data:{"username":"admin","password":"e7cf3ef4f17c3999a94f2c6f612e8a888e5b1026878e4e19398b23bd38ec221a"},
}
public authenticate() {
this.messages.next(this.authenticateMessage);
}
constructor(wsService: WebsocketService) {
this.messages = <Subject<Message>>wsService
.connect(WEBSOCKET_URL)
.map((response: MessageEvent): Message => {
let data = JSON.parse(response.data);
// variables aren't consistent yet. Here's a hack!
var dataData = data.Data === undefined ? data.data : data.Data;
var eventEvent = data.Event === undefined ? data.event : data.Event;
return {
Event: eventEvent,
data: dataData,
Exchange: data.exchange,
AssetType: data.assetType
}
});
}
}

View File

@@ -0,0 +1,15 @@
import { TestBed, inject } from '@angular/core/testing';
import { WebsocketResponseHandlerService } from './websocket-response-handler.service';
describe('WebsocketHandlerService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [WebsocketResponseHandlerService]
});
});
it('should be created', inject([WebsocketResponseHandlerService], (service: WebsocketResponseHandlerService) => {
expect(service).toBeTruthy();
}));
});

View File

@@ -0,0 +1,37 @@
import { NgModule, Injectable, Optional, SkipSelf } from '@angular/core';
import { Observable, Subject } from 'rxjs/Rx';
import { WebsocketService } from './../../services/websocket/websocket.service';
import { WebSocketMessage } from './../../shared/classes/websocket';
const WEBSOCKET_URL = 'ws://localhost:9050/ws';
@NgModule({
})
export class WebsocketResponseHandlerService {
public messages: Subject<any>;
public shared: Observable<WebSocketMessage>;
public isConnected :boolean = false;
constructor(@Optional() @SkipSelf() parentModule: WebsocketResponseHandlerService, wsService: WebsocketService) {
this.messages = <Subject<WebSocketMessage>>wsService
.connect(WEBSOCKET_URL)
.map((response: MessageEvent): WebSocketMessage => {
this.isConnected = wsService.isConnected;
let websocketResponseMessage = JSON.parse(response.data);
var websocketResponseData = websocketResponseMessage.Data === undefined ? websocketResponseMessage.data : websocketResponseMessage.Data;
var websocketResponseEvent = websocketResponseMessage.Event === undefined ? websocketResponseMessage.event : websocketResponseMessage.Event;
let responseMessage = new WebSocketMessage();
responseMessage.event = websocketResponseEvent;
responseMessage.data = websocketResponseData;
responseMessage.exchange = websocketResponseMessage.exchange;
responseMessage.assetType = websocketResponseMessage.assetType;
return responseMessage;
});
this.isConnected = wsService.isConnected;
this.shared = this.messages.share(); //multicast
}
}

View File

@@ -1,45 +1,62 @@
import { Injectable } from '@angular/core';
import {Subject, Observable, Observer } from 'rxjs/Rx';
import { Injectable, Optional, SkipSelf, NgModule } from '@angular/core';
import { Subject, Observable, Observer } from 'rxjs/Rx';
import { WebSocketMessage } from './../../shared/classes/websocket';
@Injectable()
@NgModule()
export class WebsocketService {
constructor() { }
public isConnected :boolean = false;
constructor (@Optional() @SkipSelf() parentModule: WebsocketService) {
if (parentModule) {
throw new Error(
'WebsocketService is already loaded. Import it in the AppModule only');
}
}
private subject: Subject<MessageEvent>;
public connect(url): Subject<MessageEvent> {
if (!this.subject) {
this.subject = this.create(url);
}
}
return this.subject;
}
private authenticateMessage = {
Event:'auth',
data:{"username":"admin","password":"e7cf3ef4f17c3999a94f2c6f612e8a888e5b1026878e4e19398b23bd38ec221a"},
}
private isAuth = false;
private create(url): Subject<MessageEvent> {
let ws = new WebSocket(url);
let observable = Observable.create(
(obs: Observer<MessageEvent>) => {
ws.onmessage = obs.next.bind(obs);
ws.onerror = obs.error.bind(obs);
ws.onclose = obs.complete.bind(obs);
return ws.close.bind(ws);
})
let observer = {
next: (data: any) => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify(this.authenticateMessage));
ws.send(JSON.stringify(data));
(obs: Observer<MessageEvent>) => {
ws.onmessage = obs.next.bind(obs);
ws.onerror = obs.error.bind(obs);
ws.onclose = () => {
this.isConnected = false;
obs.complete.bind(obs) };
ws.onopen = () => {
this.isConnected = true;
ws.send(JSON.stringify(WebSocketMessage.CreateAuthenticationMessage()));
};
return ws.close.bind(ws);
})
let observer = {
next: (data: any) => {
var counter = 0;
var interval = setInterval(() => {
if (counter == 10) {
clearInterval(interval);
}
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify(data));
clearInterval(interval);
this.isConnected = true;
}
counter++;
}, 400);
if (ws.readyState !== WebSocket.OPEN) {
new Error("Failed to send message to websocket after 10 attempts");
this.isConnected = false;
}
}
}
}
return Subject.create(observer, observable);
}
return Subject.create(observer, observable);
}
}

View File

@@ -1,3 +1 @@
<div *ngIf="showTicker" class="one-time-animation" >
<p>{{message}}</p>
</div>
{{tickerCard.Exchange}} {{tickerCard.CurrencyPair}} Last: {{this.tickerCard.Last}}

View File

@@ -1,61 +1,86 @@
import { Component, OnInit } from '@angular/core';
import { WebsocketHandlerService } from './../../services/websocket-handler/websocket-handler.service';
import {Component, OnInit, OnDestroy }from '@angular/core';
import {WebsocketResponseHandlerService }from './../../services/websocket-response-handler/websocket-response-handler.service';
import {WebSocketMessageType }from './../../shared/classes/websocket';
@Component({
selector: 'app-all-updates-ticker',
templateUrl: './all-updates-ticker.component.html',
styleUrls: ['./all-updates-ticker.component.scss']
@Component( {
selector:'app-all-updates-ticker',
templateUrl:'./all-updates-ticker.component.html',
styleUrls:['./all-updates-ticker.component.scss'],
})
export class AllEnabledCurrencyTickersComponent implements OnInit {
private ws: WebsocketHandlerService;
allCurrencies:ExchangeCurrency[];
tickerCard: TickerUpdate;
showTicker:boolean;
message:string;
allCurrencies:ExchangeCurrency[] = < ExchangeCurrency[] > []; ;
private ws:WebsocketResponseHandlerService;
tickerCard:TickerUpdate = new TickerUpdate();
showTicker:boolean = true;
message:string;
constructor(private websocketHandler: WebsocketHandlerService) {
this.ws = websocketHandler;
this.allCurrencies = <ExchangeCurrency[]>[];
this.ws.messages.subscribe(msg => {
if (msg.Event === 'ticker_update') {
this.showTicker = false;
var modal = <ExchangeCurrency>{};
modal.currencyPair = msg.data.CurrencyPair;
modal.exchangeName = msg.Exchange;
var ticker = <TickerUpdate>msg.data;
this.tickerCard = ticker;
this.tickerCard.Exchange = msg.Exchange;
if(this.tickerCard.Last > 0) {
this.showTicker = true;
this.message = this.tickerCard.Exchange + " " + this.tickerCard.CurrencyPair + " Last: " + this.tickerCard.Last;
constructor(private websocketHandler: WebsocketResponseHandlerService) {
this.tickerCard.Exchange = "Loading";
this.tickerCard.CurrencyPair = "...";
this.tickerCard.Last = -1;
this.ws = websocketHandler;
this.ws.shared.subscribe(msg => {
if (msg.event === WebSocketMessageType.TickerUpdate) {
if (window.localStorage["selectedExchange"] !== undefined &&
window.localStorage["selectedCurrency"] !== undefined) {
this.tickerCard.Exchange = window.localStorage["selectedExchange"];
this.tickerCard.CurrencyPair = window.localStorage["selectedCurrency"];
if (msg.exchange == window.localStorage["selectedExchange"]) {
if (this.stripCurrencyCharacters(msg.data.CurrencyPair) == window.localStorage["selectedCurrency"]) {
this.updateTicker(msg)
}
}
}else {
this.updateTicker(msg)
}
}
});
});
}
ngOnInit() { }
private updateTicker(msg:any):void {
var modal = < ExchangeCurrency > {};
modal.currencyPair = msg.data.CurrencyPair;
modal.exchangeName = msg.exchange;
var ticker = < TickerUpdate > msg.data;
this.tickerCard = ticker;
this.tickerCard.Exchange = msg.exchange;
this.message = this.tickerCard.Exchange + " " + this.tickerCard.CurrencyPair + " Last: " + this.tickerCard.Last;
}
ngOnInit() {
}
private stripCurrencyCharacters(name:string):string {
name = name.replace('_', '');
name = name.replace('-', '');
name = name.replace(' ', '');
name = name.toLocaleUpperCase();
return name;
}
}
export interface ExchangeCurrency {
currencyPair: string;
exchangeName:string;
currencyPair:string;
exchangeName:string;
}
export interface CurrencyPair {
delimiter: string;
first_currency: string;
second_currency: string;
delimiter:string;
first_currency:string;
second_currency:string;
}
export interface TickerUpdate {
Pair: CurrencyPair;
CurrencyPair: string;
Last: number;
High: number;
Low: number;
Bid: number;
Ask: number;
Volume: number;
PriceATH: number;
Exchange:string;
export class TickerUpdate {
Pair:CurrencyPair;
CurrencyPair:string;
Last:number;
High:number;
Low:number;
Bid:number;
Ask:number;
Volume:number;
PriceATH:number;
Exchange:string;
}

View File

@@ -1,12 +1,24 @@
<form class="form-content">
<div *ngIf="showErrorMessage">
<h4>{{chooseCurrencyMessage}}</h4>
<button routerLink="/exchange-grid" mat-raised-button color="primary">Choose currency</button>
</div>
<div *ngIf="!showErrorMessage">
<mat-form-field>
<input matInput disabled="disabled" name="exchange" [ngModel]="exchangeName" placeholder="Exchange">
</mat-form-field>
<mat-form-field>
<input matInput disabled="disabled" name="currency" [ngModel]="currencyName" placeholder="Currency">
</mat-form-field>
</div>
<mat-form-field>
<input matInput name="smsUsername" placeholder="Amount">
<input matInput name="amount" placeholder="Amount">
</mat-form-field>
<mat-form-field>
<input matInput name="smsPassword" placeholder="Offer">
<input matInput name="offer" placeholder="Offer">
</mat-form-field>
<div mat-line></div>
<div class="spacer">
<button mat-raised-button color="primary">CONFIRM BUY</button>
<button [disabled]="showErrorMessage" mat-raised-button color="primary">CONFIRM BUY</button>
</div>
</form>

View File

@@ -6,9 +6,20 @@ import { Component, OnInit } from '@angular/core';
styleUrls: ['./buy-form.component.scss']
})
export class BuyFormComponent implements OnInit {
public exchangeName :string;
public currencyName :string;
public chooseCurrencyMessage :string = "Please select a currency";
public showErrorMessage :boolean;
constructor() { }
ngOnInit() {
if (window.localStorage["selectedExchange"] !== undefined &&
window.localStorage["selectedCurrency"] !== undefined) {
this.exchangeName = window.localStorage["selectedExchange"];
this.currencyName = window.localStorage["selectedCurrency"];
} else {
this.showErrorMessage = true;
}
}
}

View File

@@ -0,0 +1,175 @@
export class Config {
Name: string;
EncryptConfig?: number;
Cryptocurrencies: string;
CurrencyExchangeProvider: string;
CurrencyPairFormat: CurrencyPairFormat;
PortfolioAddresses: PortfolioAddresses;
SMSGlobal: SMSGlobal;
Webserver: Webserver;
Exchanges: Exchange[];
public isConfigCacheValid() : boolean {
let dateStored = +new Date(window.localStorage['configDate']);
let dateNow = +new Date();
var dateDifference = Math.abs(dateNow - dateStored)
var diffMins = Math.floor((dateDifference / 1000) / 60);
(diffMins)
if(isNaN(new Date(dateStored).getTime()) || diffMins > 15) {
return false;
}
else {
return true
}
}
public setConfig(data: any) : void {
var configData = <Config>data;
this.Cryptocurrencies = configData.Cryptocurrencies
this.CurrencyExchangeProvider = configData.CurrencyExchangeProvider
this.Exchanges = configData.Exchanges
this.CurrencyPairFormat = configData.CurrencyPairFormat
this.EncryptConfig = configData.EncryptConfig
this.Exchanges = configData.Exchanges
this.Name = configData.Name
this.PortfolioAddresses = configData.PortfolioAddresses
this.SMSGlobal = configData.SMSGlobal
this.Webserver = configData.Webserver
this.fromArrayToRedux()
}
public fromArrayToRedux() : void {
for (var i = 0; i < this.Exchanges.length; i++) {
this.Exchanges[i].Pairs = new Array<CurrencyPairRedux>();
var avail = this.Exchanges[i].AvailablePairs.split(',');
var enabled = this.Exchanges[i].EnabledPairs.split(',');
for (var j = 0; j < avail.length; j++) {
var currencyPair = new CurrencyPairRedux();
currencyPair.Name = avail[j]
currencyPair.ParsedName = this.stripCurrencyCharacters(avail[j]);
if (enabled.indexOf(avail[j]) > 0) {
currencyPair.Enabled = true;
} else {
currencyPair.Enabled = false;
}
this.Exchanges[i].Pairs.push(currencyPair);
}
}
window.localStorage['config'] = JSON.stringify(this);
window.localStorage['configDate'] = new Date().toString();
}
public parseSettings() : void {
}
private stripCurrencyCharacters(name:string) :string {
name = name.replace('_', '');
name = name.replace('-', '');
name = name.replace(' ', '');
name = name.toLocaleUpperCase();
return name;
}
public fromReduxToArray() : void {
for (var i = 0; i < this.Exchanges.length; i++) {
// Step 1, iterate over the Pairs
var enabled = this.Exchanges[i].EnabledPairs.split(',');
for (var j = 0; j < this.Exchanges[i].Pairs.length; j++) {
if (this.Exchanges[i].Pairs[j].Enabled) {
if (enabled.indexOf(this.Exchanges[i].Pairs[j].Name) == -1) {
// Step 3 if its not in the enabled list, add it
enabled.push(this.Exchanges[i].Pairs[j].Name);
} else {
}
} else {
if (enabled.indexOf(this.Exchanges[i].Pairs[j].Name) > -1) {
enabled.splice(enabled.indexOf(this.Exchanges[i].Pairs[j].Name), 1);
} else {
}
}
}
//Step 4 JSONifiy the enabled list and set it to the this.settings.Exchanges[i].EnabledPairs
this.Exchanges[i].EnabledPairs = enabled.join();
}
}
}
export class CurrencyPairRedux {
Name: string;
ParsedName: string;
Enabled: boolean;
}
export interface CurrencyPairFormat {
Uppercase: boolean;
Delimiter: string;
}
export interface PortfolioAddresses {
Addresses?: any;
}
export interface Contact {
Name: string;
Number: string;
Enabled: boolean;
}
export interface SMSGlobal {
Enabled: boolean;
Username: string;
Password: string;
Contacts: Contact[];
}
export interface Webserver {
Enabled: boolean;
AdminUsername: string;
AdminPassword: string;
ListenAddress: string;
WebsocketConnectionLimit: number;
WebsocketAllowInsecureOrigin: boolean;
}
export interface ConfigCurrencyPairFormat {
Uppercase: boolean;
Index: string;
Delimiter: string;
}
export interface RequestCurrencyPairFormat {
Uppercase: boolean;
Index: string;
Delimiter: string;
Separator: string;
}
export interface Exchange {
Name: string;
Enabled: boolean;
Verbose: boolean;
Websocket: boolean;
RESTPollingDelay: number;
AuthenticatedAPISupport: boolean;
APIKey: string;
APISecret: string;
AvailablePairs: string;
EnabledPairs: string;
BaseCurrencies: string;
AssetTypes: string;
ConfigCurrencyPairFormat: ConfigCurrencyPairFormat;
RequestCurrencyPairFormat: RequestCurrencyPairFormat;
ClientID: string;
Pairs: CurrencyPairRedux[];
}

View File

@@ -0,0 +1,45 @@
import { Component, OnInit, OnDestroy, Pipe, PipeTransform } from '@angular/core';
import { CurrencyPairRedux } from './../../shared/classes/config';
@Pipe({
name: 'iterateMap'
})
export class IterateMapPipe implements PipeTransform {
transform(iterable: any, args: any[]): any {
let result = [];
if (iterable.entries) {
iterable.forEach((key, value) => {
result.push({
key,
value
});
});
} else {
for (let key in iterable) {
if (iterable.hasOwnProperty(key)) {
result.push({
key,
value: iterable[key]
});
}
}
}
return result;
}
}
@Pipe({
name: 'enabledCurrencies'
})
export class EnabledCurrenciesPipe implements PipeTransform {
transform(items: CurrencyPairRedux[], args: any[]): any {
if (!items) {
return items;
}
return items.filter(item => item.Enabled === true);
}
}

View File

@@ -0,0 +1,32 @@
export class WebSocketMessage {
public event: string;
public data: any;
public exchange: string;
public assetType: string;
public static CreateAuthenticationMessage(): WebSocketMessage {
var response = new WebSocketMessage();
response.event = WebSocketMessageType.Auth;
response.data = { "username": window.sessionStorage["username"], "password": window.sessionStorage["password"] };
return response;
};
public static GetSettingsMessage() : WebSocketMessage {
var response = new WebSocketMessage();
response.event = WebSocketMessageType.GetConfig;
response.data = null;
return response;
}
}
export class WebSocketMessageType {
public static Auth: string = "auth";
public static GetConfig: string = "GetConfig";
public static SaveConfig: string = "SaveConfig";
public static GetPortfolio: string = "GetPortfolio";
public static TickerUpdate: string = "ticker_update";
}

View File

@@ -7,7 +7,6 @@
</a>
<app-selected-currency></app-selected-currency>
<div class="flex-spacer"></div>
<app-all-updates-ticker></app-all-updates-ticker>
<theme-picker></theme-picker>
&nbsp;
&nbsp;

View File

@@ -64,7 +64,7 @@ export class PriceHistoryComponent implements OnInit {
public options = {
"type": "serial",
"theme": "light",
"theme": "dark",
"dataDateFormat": "YYYY-MM-DD",
"zoomOutOnDataUpdate": false,
"valueAxes": [{
@@ -158,7 +158,6 @@ export class PriceHistoryComponent implements OnInit {
e.chart.firstPoint = e.item;
}
//console.log(e.item);
e.chart.validateData();
}
}],

View File

@@ -1,4 +1,5 @@
<button mat-button routerLink="exchange-grid" matTooltip="Change currency">POLONIEX: BTC_USD (placeholder)</button>
<button class="currency-button" mat-button routerLink="exchange-grid" matTooltip="Change currency"><app-all-updates-ticker></app-all-updates-ticker></button>
<button mat-icon-button routerLink="currency-list" matTooltip="View currency list">
<mat-icon>
view_list

View File

@@ -0,0 +1,4 @@
.currency-button {
width: 20rem;
text-align: left;
}

View File

@@ -1,12 +1,24 @@
<form class="form-content">
<mat-form-field>
<input matInput name="smsUsername" placeholder="Amount">
</mat-form-field>
<mat-form-field>
<input matInput name="smsPassword" placeholder="Offer">
</mat-form-field>
<div mat-line></div>
<div *ngIf="showErrorMessage">
<h4>{{chooseCurrencyMessage}}</h4>
<button routerLink="/exchange-grid" mat-raised-button color="primary">Choose currency</button>
</div>
<div *ngIf="!showErrorMessage">
<mat-form-field>
<input matInput disabled="disabled" name="exchange" [ngModel]="exchangeName" placeholder="Exchange">
</mat-form-field>
<mat-form-field>
<input matInput disabled="disabled" name="currency" [ngModel]="currencyName" placeholder="Currency">
</mat-form-field>
</div>
<mat-form-field>
<input matInput name="amount" placeholder="Amount">
</mat-form-field>
<mat-form-field>
<input matInput name="offer" placeholder="Offer">
</mat-form-field>
<div mat-line></div>
<div class="spacer">
<button mat-raised-button color="primary">CONFIRM SELL</button>
</div>
</form>
<button [disabled]="showErrorMessage" mat-raised-button color="primary">CONFIRM SELL</button>
</div>
</form>

View File

@@ -6,10 +6,20 @@ import { Component, OnInit } from '@angular/core';
styleUrls: ['./sell-form.component.scss']
})
export class SellFormComponent implements OnInit {
constructor() { }
ngOnInit() {
}
public exchangeName :string;
public currencyName :string;
public chooseCurrencyMessage :string = "Please select a currency";
public showErrorMessage :boolean;
constructor() { }
ngOnInit() {
if (window.localStorage["selectedExchange"] !== undefined &&
window.localStorage["selectedCurrency"] !== undefined) {
this.exchangeName = window.localStorage["selectedExchange"];
this.currencyName = window.localStorage["selectedCurrency"];
} else {
this.showErrorMessage = true;
}
}
}

View File

@@ -73,7 +73,7 @@ export class ThemePickerComponent {
if (theme.isDefault) {
this.styleManager.removeStyle('theme');
} else {
this.styleManager.setStyle('theme', `assets/${theme.href}`);
this.styleManager.setStyle('theme', `assets/themes/${theme.href}`);
}
if (this.currentTheme) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

View File

@@ -0,0 +1,106 @@
i.cc.ARCH, i.cc.ARCH-alt { color: #002652; }
i.cc.BANX, i.cc.BANX-alt { color: #225BA6; }
i.cc.BC, i.cc.BC-alt { color: #202121; }
i.cc.BCN, i.cc.BCN-alt { color: #964F51; }
i.cc.BTC, i.cc.BTC-alt { color: #F7931A; }
i.cc.BTCD, i.cc.BTCD-alt { color: #2A72DC; }
i.cc.BTS, i.cc.BTS-alt { color: #03A9E0; }
i.cc.DASH, i.cc.DASH-alt { color: #1c75bc; }
i.cc.DOGE, i.cc.DOGE-alt { color: #BA9F33; }
i.cc.FC2, i.cc.FC2-alt { color: #040405; }
i.cc.FTC, i.cc.FTC-alt { color: #679EF1; }
i.cc.GEMZ, i.cc.GEMZ-alt { color: #e86060; }
i.cc.GRC, i.cc.GRC-alt { color: #88A13C; }
i.cc.IFC, i.cc.IFC-alt { color: #ed272d; }
i.cc.KORE, i.cc.KORE-alt { color: #DF4124; }
i.cc.LTC, i.cc.LTC-alt { color: #838383; }
i.cc.MAID, i.cc.MAID-alt { color: #5492D6; }
i.cc.MSC, i.cc.MSC-alt { color: #1D4983; }
i.cc.NBT { color: #FFC93D; }
i.cc.NMC, i.cc.NMC-alt { color: #6787B7; }
i.cc.NOTE, i.cc.NOTE-alt { color: #42daff; }
i.cc.NXT, i.cc.NXT-alt { color: #008FBB; }
i.cc.OPAL, i.cc.OPAL-alt { color: #7193AA; }
i.cc.POT, i.cc.POT-alt { color: #105B2F; }
i.cc.PPC, i.cc.PPC-alt { color: #3FA30C; }
i.cc.QRK, i.cc.QRK-alt { color: #22AABF; }
i.cc.RBT, i.cc.RBT-alt { color: #0d4982; }
i.cc.SDC, i.cc.SDC-alt { color: #981D2D; }
i.cc.STR, i.cc.STR-alt { color: #08B5E5; }
i.cc.SYNC, i.cc.SYNC-alt { color: #008DD2; }
i.cc.UNITY, i.cc.UNITY-alt { color: #ED8527; }
i.cc.VIOR, i.cc.VIOR-alt { color: #1F52A4; }
i.cc.VPN, i.cc.VPN-alt { color: #589700; }
i.cc.VRC, i.cc.VRC-alt { color: #418bca; }
i.cc.VTC, i.cc.VTC-alt { color: #1b5c2e; }
i.cc.XCP, i.cc.XCP-alt { color: #EC1550; }
i.cc.XEM, i.cc.XEM-alt { color: #41bf76; }
i.cc.XMR { color: #FF6600; }
i.cc.XRP, i.cc.XRP-alt { color: #346AA9; }
i.cc.YBC, i.cc.YBC-alt { color: #D6C154; }
i.cc.DMD, i.cc.DMD-alt { color: #5497b2; }
i.cc.FRK, i.cc.FRK-alt { color: #0633cd; }
i.cc.IOC, i.cc.IOC-alt { color: #2fa3de; }
i.cc.LDOGE, i.cc.LDOGE-alt { color: #ffcc00; }
i.cc.MTR, i.cc.MTR-alt { color: #b92429; }
i.cc.MUE, i.cc.MUE-alt { color: #f5a10e; }
i.cc.XAI, i.cc.XAI-alt { color: #2ef99f; }
i.cc.XBS, i.cc.XBS-alt { color: #d3261d; }
i.cc.XPM, i.cc.XPM-alt { color: #e5b625; }
i.cc.BAY, i.cc.BAY-alt { color: #584ba1; }
i.cc.DGB, i.cc.DGB-alt { color: #0066cc; }
i.cc.EMC, i.cc.EMC-alt { color: #674c8c; }
i.cc.ETH, i.cc.ETH-alt { color: #282828; }
i.cc.MINT, i.cc.MINT-alt { color: #006835; }
i.cc.MONA, i.cc.MONA-alt { color: #a99364; }
i.cc.MRC { color: #4279bd; }
i.cc.NEU, i.cc.NEU-alt { color: #2983c0; }
i.cc.NVC, i.cc.NVC-alt { color: #ecab41; }
i.cc.AEON, i.cc.AEON-alt { color: #164450; }
i.cc.AMP, i.cc.AMP-alt { color: #048DD2; }
i.cc.ANC, i.cc.ANC-alt { color: #000; }
i.cc.BTA { color: #210094; }
i.cc.CLAM, i.cc.CLAM-alt { color: #D6AB31; }
i.cc.CLOAK, i.cc.CLOAK-alt { color: #DF3F1E; }
i.cc.DCR, i.cc.DCR-alt { color: #43A2CA; }
i.cc.NEOS, i.cc.NEOS-alt { color: #3771B1; }
i.cc.NLG, i.cc.NLG-alt { color: #003E7E; }
i.cc.OK, i.cc.OK-alt { color: #0165A4; }
i.cc.OMNI, i.cc.OMNI-alt { color: #18347E; }
i.cc.RBY, i.cc.RBY-alt { color: #D31F26; }
i.cc.SCOT, i.cc.SCOT-alt { color: #3498DB; }
i.cc.SJCX, i.cc.SJCX-alt { color: #003366; }
i.cc.START, i.cc.START-alt { color: #01AEF0; }
i.cc.SYS, i.cc.SYS-alt { color: #0098DA; }
i.cc.VNL, i.cc.VNL-alt { color: #404249; }
i.cc.TX, i.cc.TX-alt { color: #1F8BCC; }
i.cc.XVG, i.cc.XVG-alt { color: #42AFB2; }
i.cc.FCT, i.cc.FCT-alt { color: #2175BB; }
i.cc.GDC, i.cc.GDC-alt { color: #E9A226; }
i.cc.JBS, i.cc.JBS-alt { color: #1A8BCD; }
i.cc.LISK, i.cc.LISK-alt { color: #1A6896; }
i.cc.PIGGY, i.cc.PIGGY-alt { color: #F27A7A; }
i.cc.RBIES, i.cc.RBIES-alt { color: #C62436; }
i.cc.SAR, i.cc.SAR-alt { color: #1B72B8; }
i.cc.SLG, i.cc.SLG-alt { color: #5A6875; }
i.cc.USDT, i.cc.USDT-alt { color: #2CA07A; }
i.cc.ZEIT, i.cc.ZEIT-alt { color: #ACACAC; }
i.cc.DGD, i.cc.DGX { color: #D8A24A; }
i.cc.ADC, i.cc.ADC-alt { color: #3CB0E5; }
i.cc.BSD, i.cc.BSD-alt { color: #1186E7; }
i.cc.DAO, i.cc.DAO-alt { color: #FF3B3B; }
i.cc.ERC, i.cc.ERC-alt { color: #101E84; }
i.cc.ETC, i.cc.ETC-alt { color: #669073; }
i.cc.GLD, i.cc.GLD-alt { color: #E8BE24; }
i.cc.GRS { color: #648FA0; }
i.cc.KOBO { color: #80C342; }
i.cc.LBC, i.cc.LBC-alt { color: #015C47; }
i.cc.PINK, i.cc.PINK-alt { color: #ED31CA; }
i.cc.RDD, i.cc.RDD-alt { color: #ED1C24; }
i.cc.RISE, i.cc.RISE-alt { color: #43CEA2; }
i.cc.SIA, i.cc.SIA-alt { color: #00CBA0; }
i.cc.SLS, i.cc.SLS-alt { color: #1EB549; }
i.cc.SNRG, i.cc.SNRG-alt { color: #160363; }
i.cc.STEEM, i.cc.STEEM-alt { color: #1A5099; }
i.cc.STRAT, i.cc.STRAT-alt { color: #33C7F5; }
i.cc.SWIFT, i.cc.SWIFT-alt { color: #428BCA; }

View File

@@ -0,0 +1,645 @@
@font-face {
font-family: 'cryptocoins';
src: url('./../fonts/cryptocoins.eot?d2eit9');
src: url('./../fonts/cryptocoins.eot?d2eit9#iefix') format('embedded-opentype'),
url('./../fonts/cryptocoins.ttf?d2eit9') format('truetype'),
url('./../fonts/cryptocoins.woff?d2eit9') format('woff'),
url('./../fonts/cryptocoins.svg?d2eit9#cryptocoins') format('svg');
font-weight: normal;
font-style: normal;
}
i.cc {
/* use !important to prevent issues with browser extensions that change fonts */
font-family: 'cryptocoins' !important;
speak: none;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
/* Better Font Rendering =========== */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
i.cc.SAR:before {
content: "\e900";
}
i.cc.SAR-alt:before {
content: "\e901";
}
i.cc.SCOT:before {
content: "\e902";
}
i.cc.SCOT-alt:before {
content: "\e903";
}
i.cc.SDC:before {
content: "\e904";
}
i.cc.SDC-alt:before {
content: "\e905";
}
i.cc.SIA:before {
content: "\e906";
}
i.cc.SIA-alt:before {
content: "\e907";
}
i.cc.SJCX:before {
content: "\e908";
}
i.cc.SJCX-alt:before {
content: "\e909";
}
i.cc.SLG:before {
content: "\e90a";
}
i.cc.SLG-alt:before {
content: "\e90b";
}
i.cc.SLS:before {
content: "\e90c";
}
i.cc.SLS-alt:before {
content: "\e90d";
}
i.cc.SNRG:before {
content: "\e90e";
}
i.cc.SNRG-alt:before {
content: "\e90f";
}
i.cc.START:before {
content: "\e910";
}
i.cc.START-alt:before {
content: "\e911";
}
i.cc.STEEM:before {
content: "\e912";
}
i.cc.STEEM-alt:before {
content: "\e913";
}
i.cc.STR:before {
content: "\e914";
}
i.cc.STR-alt:before {
content: "\e915";
}
i.cc.STRAT:before {
content: "\e916";
}
i.cc.STRAT-alt:before {
content: "\e917";
}
i.cc.SWIFT:before {
content: "\e918";
}
i.cc.SWIFT-alt:before {
content: "\e919";
}
i.cc.SYNC:before {
content: "\e91a";
}
i.cc.SYNC-alt:before {
content: "\e91b";
}
i.cc.SYS:before {
content: "\e91c";
}
i.cc.SYS-alt:before {
content: "\e91d";
}
i.cc.TX:before {
content: "\e91e";
}
i.cc.TX-alt:before {
content: "\e91f";
}
i.cc.UNITY:before {
content: "\e920";
}
i.cc.UNITY-alt:before {
content: "\e921";
}
i.cc.USDT:before {
content: "\e922";
}
i.cc.USDT-alt:before {
content: "\e923";
}
i.cc.VIOR:before {
content: "\e924";
}
i.cc.VIOR-alt:before {
content: "\e925";
}
i.cc.VNL:before {
content: "\e926";
}
i.cc.VNL-alt:before {
content: "\e927";
}
i.cc.VPN:before {
content: "\e928";
}
i.cc.VPN-alt:before {
content: "\e929";
}
i.cc.VRC:before {
content: "\e92a";
}
i.cc.VRC-alt:before {
content: "\e92b";
}
i.cc.VTC:before {
content: "\e92c";
}
i.cc.VTC-alt:before {
content: "\e92d";
}
i.cc.XAI:before {
content: "\e92e";
}
i.cc.XAI-alt:before {
content: "\e92f";
}
i.cc.XBS:before {
content: "\e930";
}
i.cc.XBS-alt:before {
content: "\e931";
}
i.cc.XCP:before {
content: "\e932";
}
i.cc.XCP-alt:before {
content: "\e933";
}
i.cc.XEM:before {
content: "\e934";
}
i.cc.XEM-alt:before {
content: "\e935";
}
i.cc.XMR:before {
content: "\e936";
}
i.cc.XPM:before {
content: "\e937";
}
i.cc.XPM-alt:before {
content: "\e938";
}
i.cc.XRP:before {
content: "\e939";
}
i.cc.XRP-alt:before {
content: "\e93a";
}
i.cc.XVG:before {
content: "\e93b";
}
i.cc.XVG-alt:before {
content: "\e93c";
}
i.cc.YBC:before {
content: "\e93d";
}
i.cc.YBC-alt:before {
content: "\e93e";
}
i.cc.ZEIT:before {
content: "\e93f";
}
i.cc.ZEIT-alt:before {
content: "\e940";
}
i.cc.MAID:before {
content: "\e941";
}
i.cc.MAID-alt:before {
content: "\e942";
}
i.cc.MINT:before {
content: "\e943";
}
i.cc.MINT-alt:before {
content: "\e944";
}
i.cc.MONA:before {
content: "\e945";
}
i.cc.MONA-alt:before {
content: "\e946";
}
i.cc.MRC:before {
content: "\e947";
}
i.cc.MSC:before {
content: "\e948";
}
i.cc.MSC-alt:before {
content: "\e949";
}
i.cc.MTR:before {
content: "\e94a";
}
i.cc.MTR-alt:before {
content: "\e94b";
}
i.cc.MUE:before {
content: "\e94c";
}
i.cc.MUE-alt:before {
content: "\e94d";
}
i.cc.NBT:before {
content: "\e94e";
}
i.cc.NEOS:before {
content: "\e94f";
}
i.cc.NEOS-alt:before {
content: "\e950";
}
i.cc.NEU:before {
content: "\e951";
}
i.cc.NEU-alt:before {
content: "\e952";
}
i.cc.NLG:before {
content: "\e953";
}
i.cc.NLG-alt:before {
content: "\e954";
}
i.cc.NMC:before {
content: "\e955";
}
i.cc.NMC-alt:before {
content: "\e956";
}
i.cc.NOTE:before {
content: "\e957";
}
i.cc.NOTE-alt:before {
content: "\e958";
}
i.cc.NVC:before {
content: "\e959";
}
i.cc.NVC-alt:before {
content: "\e95a";
}
i.cc.NXT:before {
content: "\e95b";
}
i.cc.NXT-alt:before {
content: "\e95c";
}
i.cc.OK:before {
content: "\e95d";
}
i.cc.OK-alt:before {
content: "\e95e";
}
i.cc.OMNI:before {
content: "\e95f";
}
i.cc.OMNI-alt:before {
content: "\e960";
}
i.cc.OPAL:before {
content: "\e961";
}
i.cc.OPAL-alt:before {
content: "\e962";
}
i.cc.PIGGY:before {
content: "\e963";
}
i.cc.PIGGY-alt:before {
content: "\e964";
}
i.cc.PINK:before {
content: "\e965";
}
i.cc.PINK-alt:before {
content: "\e966";
}
i.cc.POT:before {
content: "\e967";
}
i.cc.POT-alt:before {
content: "\e968";
}
i.cc.PPC:before {
content: "\e969";
}
i.cc.PPC-alt:before {
content: "\e96a";
}
i.cc.QRK:before {
content: "\e96b";
}
i.cc.QRK-alt:before {
content: "\e96c";
}
i.cc.RBIES:before {
content: "\e96d";
}
i.cc.RBIES-alt:before {
content: "\e96e";
}
i.cc.RBT:before {
content: "\e96f";
}
i.cc.RBT-alt:before {
content: "\e970";
}
i.cc.RBY:before {
content: "\e971";
}
i.cc.RBY-alt:before {
content: "\e972";
}
i.cc.RDD:before {
content: "\e973";
}
i.cc.RDD-alt:before {
content: "\e974";
}
i.cc.RISE:before {
content: "\e975";
}
i.cc.RISE-alt:before {
content: "\e976";
}
i.cc.GDC:before {
content: "\e977";
}
i.cc.GDC-alt:before {
content: "\e978";
}
i.cc.GEMZ:before {
content: "\e979";
}
i.cc.GEMZ-alt:before {
content: "\e97a";
}
i.cc.GLD:before {
content: "\e97b";
}
i.cc.GLD-alt:before {
content: "\e97c";
}
i.cc.GRC:before {
content: "\e97d";
}
i.cc.GRC-alt:before {
content: "\e97e";
}
i.cc.GRS:before {
content: "\e97f";
}
i.cc.IFC:before {
content: "\e980";
}
i.cc.IFC-alt:before {
content: "\e981";
}
i.cc.IOC:before {
content: "\e982";
}
i.cc.IOC-alt:before {
content: "\e983";
}
i.cc.JBS:before {
content: "\e984";
}
i.cc.JBS-alt:before {
content: "\e985";
}
i.cc.KOBO:before {
content: "\e986";
}
i.cc.KORE:before {
content: "\e987";
}
i.cc.KORE-alt:before {
content: "\e988";
}
i.cc.LBC:before {
content: "\e989";
}
i.cc.LBC-alt:before {
content: "\e98a";
}
i.cc.LDOGE:before {
content: "\e98b";
}
i.cc.LDOGE-alt:before {
content: "\e98c";
}
i.cc.LISK:before {
content: "\e98d";
}
i.cc.LISK-alt:before {
content: "\e98e";
}
i.cc.LTC:before {
content: "\e98f";
}
i.cc.LTC-alt:before {
content: "\e990";
}
i.cc.ADC:before {
content: "\e991";
}
i.cc.ADC-alt:before {
content: "\e992";
}
i.cc.AEON:before {
content: "\e993";
}
i.cc.AEON-alt:before {
content: "\e994";
}
i.cc.AMP:before {
content: "\e995";
}
i.cc.AMP-alt:before {
content: "\e996";
}
i.cc.ANC:before {
content: "\e997";
}
i.cc.ANC-alt:before {
content: "\e998";
}
i.cc.ARCH:before {
content: "\e999";
}
i.cc.ARCH-alt:before {
content: "\e99a";
}
i.cc.BANX:before {
content: "\e99b";
}
i.cc.BANX-alt:before {
content: "\e99c";
}
i.cc.BAY:before {
content: "\e99d";
}
i.cc.BAY-alt:before {
content: "\e99e";
}
i.cc.BC:before {
content: "\e99f";
}
i.cc.BC-alt:before {
content: "\e9a0";
}
i.cc.BCN:before {
content: "\e9a1";
}
i.cc.BCN-alt:before {
content: "\e9a2";
}
i.cc.BSD:before {
content: "\e9a3";
}
i.cc.BSD-alt:before {
content: "\e9a4";
}
i.cc.BTA:before {
content: "\e9a5";
}
i.cc.BTC:before {
content: "\e9a6";
}
i.cc.BTC-alt:before {
content: "\e9a7";
}
i.cc.BTCD:before {
content: "\e9a8";
}
i.cc.BTCD-alt:before {
content: "\e9a9";
}
i.cc.BTS:before {
content: "\e9aa";
}
i.cc.BTS-alt:before {
content: "\e9ab";
}
i.cc.CLAM:before {
content: "\e9ac";
}
i.cc.CLAM-alt:before {
content: "\e9ad";
}
i.cc.CLOAK:before {
content: "\e9ae";
}
i.cc.CLOAK-alt:before {
content: "\e9af";
}
i.cc.DAO:before {
content: "\e9b0";
}
i.cc.DAO-alt:before {
content: "\e9b1";
}
i.cc.DASH:before {
content: "\e9b2";
}
i.cc.DASH-alt:before {
content: "\e9b3";
}
i.cc.DCR:before {
content: "\e9b4";
}
i.cc.DCR-alt:before {
content: "\e9b5";
}
i.cc.DGB:before {
content: "\e9b6";
}
i.cc.DGB-alt:before {
content: "\e9b7";
}
i.cc.DGD:before {
content: "\e9b8";
}
i.cc.DGX:before {
content: "\e9b9";
}
i.cc.DMD:before {
content: "\e9ba";
}
i.cc.DMD-alt:before {
content: "\e9bb";
}
i.cc.DOGE:before {
content: "\e9bc";
}
i.cc.DOGE-alt:before {
content: "\e9bd";
}
i.cc.EMC:before {
content: "\e9be";
}
i.cc.EMC-alt:before {
content: "\e9bf";
}
i.cc.ERC:before {
content: "\e9c0";
}
i.cc.ERC-alt:before {
content: "\e9c1";
}
i.cc.ETC:before {
content: "\e9c2";
}
i.cc.ETC-alt:before {
content: "\e9c3";
}
i.cc.ETH:before {
content: "\e9c4";
}
i.cc.ETH-alt:before {
content: "\e9c5";
}
i.cc.FC2:before {
content: "\e9c6";
}
i.cc.FC2-alt:before {
content: "\e9c7";
}
i.cc.FCT:before {
content: "\e9c8";
}
i.cc.FCT-alt:before {
content: "\e9c9";
}
i.cc.FRK:before {
content: "\e9ca";
}
i.cc.FRK-alt:before {
content: "\e9cb";
}
i.cc.FTC:before {
content: "\e9cc";
}
i.cc.FTC-alt:before {
content: "\e9cd";
}

View File

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 268 KiB

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,7 @@
{
"PAGES": {
"HOME": {
"TITLE": "App works !"
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

View File

@@ -240,7 +240,7 @@ deltaY:b,delta2X:c,delta2Y:e,index:this.index}),this.prevDeltaX=a,this.prevDelta
this.mouseY,"changed"))},handleMouseOut:function(){this.enabled&&this.rolledOver&&(this.leaveCursor||this.setIndex(void 0),this.forceShow=!1,this.hideCursor(),this.rolledOver=!1)},showCursorAt:function(a){var b=this.chart.categoryAxis;b&&this.setPosition(b.categoryToCoordinate(a),a)},setPosition:function(a,b){var c=this.chart,e=c.categoryAxis;if(e){var d,f;void 0===b&&(b=e.coordinateToValue(a));e.showBalloonAt(b,a);this.forceShow=!0;e.stickBalloonToCategory?c.rotate?this.fixHLine(a,0):this.fixVLine(a,
0):(this.showCursor(),c.rotate?this.hhLine.translate(0,a):this.vvLine.translate(a,0));c.rotate?d=a:f=a;c.rotate?(this.vvLine&&this.vvLine.hide(),this.hhLine&&this.hhLine.show()):(this.hhLine&&this.hhLine.hide(),this.vvLine&&this.vvLine.show());this.updateFullLine();this.isHidden=!1;this.dispatchMovedEvent(f,d,"moved",!0)}},enableDrawing:function(a){this.enabled=!a;this.hideCursor();this.drawing=a},syncWithCursor:function(a,b){clearTimeout(this.syncTO);a&&(a.isHidden?this.hideCursor(!0):this.syncWithCursorReal(a,
b))},isZooming:function(a){this.zooming=a},syncWithCursorReal:function(a,b){var c=a.vvLine,e=a.hhLine;this.index=a.index;this.forceShow=!0;this.zooming&&this.pan||this.showCursor(!0);this.hideGraphBalloons=b;this.justReleased=a.justReleased;this.zooming=a.zooming;this.index0=a.index0;this.mouseX0=a.mouseX0;this.mouseY0=a.mouseY0;this.mouse2X0=a.mouse2X0;this.mouse2Y0=a.mouse2Y0;this.timestamp0=a.timestamp0;this.prevDeltaX=a.prevDeltaX;this.prevDeltaY=a.prevDeltaY;this.prevDelta2X=a.prevDelta2X;this.prevDelta2Y=
a.prevDelta2Y;this.fx=a.fx;this.fy=a.fy;a.zooming&&this.updateSelection();var d=a.mouseX,f=a.mouseY;this.rotate?(d=NaN,this.vvLine&&this.vvLine.hide(),this.hhLine&&e&&(isNaN(a.fy)?this.hhLine.translate(0,a.mouseY):this.fixHLine(a.fy,0))):(f=NaN,this.hhLine&&this.hhLine.hide(),this.vvLine&&c&&(isNaN(a.fx)?this.vvLine.translate(a.mouseX,0):this.fixVLine(a.fx,0)));this.dispatchMovedEvent(d,f,"moved",!0)}})})();(function(){var d=window.AmCharts;d.SimpleChartScrollbar=d.Class({construct:function(a){this.createEvents("zoomed","zoomStarted","zoomEnded");this.backgroundColor="#D4D4D4";this.backgroundAlpha=1;this.selectedBackgroundColor="#EFEFEF";this.scrollDuration=this.selectedBackgroundAlpha=1;this.resizeEnabled=!0;this.hideResizeGrips=!1;this.scrollbarHeight=20;this.updateOnReleaseOnly=!1;9>document.documentMode&&(this.updateOnReleaseOnly=!0);this.dragIconHeight=this.dragIconWidth=35;this.dragIcon="dragIconRoundBig";
a.prevDelta2Y;this.fx=a.fx;this.fy=a.fy;a.zooming&&this.updateSelection();var d=a.mouseX,f=a.mouseY;this.rotate?(d=NaN,this.vvLine&&this.vvLine.hide(),this.hhLine&&e&&(isNaN(a.fy)?this.hhLine.translate(0,a.mouseY):this.fixHLine(a.fy,0))):(f=NaN,this.hhLine&&this.hhLine.hide(),this.vvLine&&c&&(isNaN(a.fx)?this.vvLine.translate(a.mouseX,0):this.fixVLine(a.fx,0)));this.dispatchMovedEvent(d,f,"moved",!0)}})})();(function(){var d=window.AmCharts;d.SimpleChartScrollbar=d.Class({construct:function(a){this.createEvents("zoomed","zoomStarted","zoomEnded");this.backgroundColor="#D4D4D4";this.backgroundAlpha=1;this.selectedBackgroundColor="#EFEFEF";this.scrollDuration=this.selectedBackgroundAlpha=1;this.resizeEnabled=!0;this.hideResizeGrips=!1;this.scrollbarHeight=20;this.updateOnReleaseOnly=!1;9>document.documentMode&&(this.updateOnReleaseOnly=!0);this.dragIconHeight=this.dragIconWidth=35;this.dragIcon="../images/dragIconRoundBig.svg";
this.dragCursorHover="cursor: move; cursor: grab; cursor: -moz-grab; cursor: -webkit-grab;";this.dragCursorDown="cursor: move; cursor: grab; cursor: -moz-grabbing; cursor: -webkit-grabbing;";this.vResizeCursor="ns-resize";this.hResizeCursor="ew-resize";this.enabled=!0;this.percentStart=this.offset=0;this.percentEnd=1;d.applyTheme(this,a,"SimpleChartScrollbar")},getPercents:function(){var a=this.getDBox(),b=a.x,c=a.y,e=a.width,a=a.height;this.rotate?(b=1-c/this.height,c=1-(c+a)/this.height):(c=b/this.width,
b=(b+e)/this.width);this.percentStart=c;this.percentEnd=b},draw:function(){var a=this;a.destroy();if(a.enabled){var b=a.chart.container,c=a.rotate,e=a.chart;e.panRequired=!0;var g=b.set();a.set=g;c?d.setCN(e,g,"scrollbar-vertical"):d.setCN(e,g,"scrollbar-horizontal");e.scrollbarsSet.push(g);var f,h;c?(f=a.scrollbarHeight,h=e.plotAreaHeight):(h=a.scrollbarHeight,f=e.plotAreaWidth);a.width=f;if((a.height=h)&&f){var k=d.rect(b,f,h,a.backgroundColor,a.backgroundAlpha,1,a.backgroundColor,a.backgroundAlpha);
d.setCN(e,k,"scrollbar-bg");a.bg=k;g.push(k);k=d.rect(b,f,h,"#000",.005);g.push(k);a.invisibleBg=k;k.click(function(){a.handleBgClick()}).mouseover(function(){a.handleMouseOver()}).mouseout(function(){a.handleMouseOut()}).touchend(function(){a.handleBgClick()});k=d.rect(b,f,h,a.selectedBackgroundColor,a.selectedBackgroundAlpha);d.setCN(e,k,"scrollbar-bg-selected");a.selectedBG=k;g.push(k);f=d.rect(b,f,h,"#000",.005);a.dragger=f;g.push(f);f.mousedown(function(b){a.handleDragStart(b)}).mouseup(function(){a.handleDragStop()}).mouseover(function(){a.handleDraggerOver()}).mouseout(function(){a.handleMouseOut()}).touchstart(function(b){a.handleDragStart(b)}).touchend(function(){a.handleDragStop()});

196
web/src/assets/js/dark.js Normal file
View File

@@ -0,0 +1,196 @@
AmCharts.themes.dark = {
AmCoordinateChart: {
colors: ["#ae85c9", "#aab9f7", "#b6d2ff", "#c9e6f2", "#c9f0e1", "#e8d685", "#e0ad63", "#d48652", "#d27362", "#495fba", "#7a629b", "#8881cc"]
},
AmPieChart: {
colors: ["#495fba", "#e8d685", "#ae85c9", "#c9f0e1", "#d48652", "#629b6d", "#719dc3", "#719dc3"]
},
AmStockChart: {
colors: ["#495fba", "#e8d685", "#ae85c9", "#c9f0e1", "#d48652", "#629b6d", "#719dc3", "#719dc3"]
},
AmSlicedChart: {
outlineAlpha: 1,
outlineThickness: 2,
labelTickColor: "#FFFFFF",
labelTickAlpha: 0.3
},
AmRectangularChart: {
zoomOutButtonColor: '#FFFFFF',
zoomOutButtonRollOverAlpha: 0.15,
zoomOutButtonImage: "lensWhite.png"
},
AxisBase: {
axisColor: "#FFFFFF",
axisAlpha: 0.3,
gridAlpha: 0.1,
gridColor: "#FFFFFF"
},
ChartScrollbar: {
backgroundColor: "#FFFFFF",
backgroundAlpha: 0.2,
graphFillAlpha: 0.5,
graphLineAlpha: 0,
selectedBackgroundColor: "#000000",
selectedBackgroundAlpha: 0.25,
gridAlpha: 0.15
},
ChartCursor: {
cursorColor: "#FFFFFF",
color: "#000000",
cursorAlpha: 0.5
},
AmLegend: {
color: "#919191"
},
AmGraph: {
lineAlpha: 0.9
},
GaugeArrow: {
color: "#FFFFFF",
alpha: 0.8,
nailAlpha: 0,
innerRadius: "40%",
nailRadius: 15,
startWidth: 15,
borderAlpha: 0.8,
nailBorderAlpha: 0
},
GaugeAxis: {
tickColor: "#FFFFFF",
tickAlpha: 1,
tickLength: 15,
minorTickLength: 8,
axisThickness: 3,
axisColor: '#FFFFFF',
axisAlpha: 1,
bandAlpha: 0.8
},
TrendLine: {
lineColor: "#c03246",
lineAlpha: 0.8
},
// ammap
AreasSettings: {
alpha: 0.8,
color: "#FFFFFF",
colorSolid: "#000000",
unlistedAreasAlpha: 0.4,
unlistedAreasColor: "#FFFFFF",
outlineColor: "#000000",
outlineAlpha: 0.5,
outlineThickness: 0.5,
rollOverColor: "#3c5bdc",
rollOverOutlineColor: "#000000",
selectedOutlineColor: "#000000",
selectedColor: "#f15135",
unlistedAreasOutlineColor: "#000000",
unlistedAreasOutlineAlpha: 0.5
},
LinesSettings: {
color: "#FFFFFF",
alpha: 0.8
},
ImagesSettings: {
alpha: 0.8,
labelColor: "#FFFFFF",
color: "#FFFFFF",
labelRollOverColor: "#3c5bdc"
},
ZoomControl: {
buttonRollOverColor: "#3c5bdc",
buttonFillColor: "#f15135",
buttonFillAlpha: 0.8,
buttonBorderColor: "#FFFFFF",
gridBackgroundColor: "#FFFFFF",
gridAlpha: 0.8
},
SmallMap: {
mapColor: "#FFFFFF",
rectangleColor: "#f15135",
backgroundColor: "#000000",
backgroundAlpha: 0.7,
borderThickness: 1,
borderAlpha: 0.8
},
// the defaults below are set using CSS syntax, you can use any existing css property
// if you don't use Stock chart, you can delete lines below
PeriodSelector: {
color: "#e7e7e7"
},
PeriodButton: {
color: "#e7e7e7",
backgroundColor: "#282828",
borderStyle: "solid",
borderColor: "#585858",
borderWidth: "1px",
MozBorderRadius: "5px",
borderRadius: "5px",
margin: "1px",
outline: "none"
},
PeriodButtonSelected: {
color: "#FFFFFF",
backgroundColor: "#414c7b",
borderStyle: "solid",
borderColor: "#3f4b80",
borderWidth: "1px",
MozBorderRadius: "5px",
borderRadius: "5px",
margin: "1px",
outline: "none"
},
PeriodInputField: {
color: "#e7e7e7",
background: "transparent",
borderStyle: "solid",
borderColor: "#585858",
borderWidth: "1px",
outline: "none"
},
DataSetSelector: {
color: "#e7e7e7",
selectedBackgroundColor: "#414c7b",
rollOverBackgroundColor: "#000000"
},
DataSetCompareList: {
color: "#e7e7e7",
borderStyle: "solid",
borderColor: "#585858",
borderWidth: "1px"
},
DataSetSelect: {
borderStyle: "solid",
borderColor: "#585858",
borderWidth: "1px",
outline: "none"
}
};

View File

Before

Width:  |  Height:  |  Size: 664 B

After

Width:  |  Height:  |  Size: 664 B

Some files were not shown because too many files have changed in this diff Show More