mirror of
https://github.com/freqtrade/frequi.git
synced 2024-11-11 02:33:51 +00:00
commit
26c9fcccd3
|
@ -1,11 +1,11 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en" data-theme="dark">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||||
|
|
||||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
BIN
src/assets/freqtrade-logo-mask.png
Normal file
BIN
src/assets/freqtrade-logo-mask.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 37 KiB |
|
@ -1,19 +1,20 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<b-nav-item-dropdown
|
<b-nav-item-dropdown
|
||||||
|
v-if="!simple"
|
||||||
id="my-nav-dropdown"
|
id="my-nav-dropdown"
|
||||||
text="Theme"
|
text="Theme"
|
||||||
toggle-class="nav-link-custom"
|
toggle-class="nav-link-custom"
|
||||||
right
|
right
|
||||||
lazy
|
lazy
|
||||||
>
|
>
|
||||||
<b-dropdown-item v-if="themes.length === 0">
|
<b-dropdown-item v-if="themeList.length === 0">
|
||||||
<b-spinner small></b-spinner> Loading Themes...
|
<b-spinner small></b-spinner> Loading Themes...
|
||||||
</b-dropdown-item>
|
</b-dropdown-item>
|
||||||
|
|
||||||
<!-- TODO Add v-b-tooltip.hover.right=="{ variant: 'className' }" for tooltip class rendered from bootswatch-->
|
<!-- TODO Add v-b-tooltip.hover.right=="{ variant: 'className' }" for tooltip class rendered from bootswatch-->
|
||||||
<b-dropdown-item-button
|
<b-dropdown-item-button
|
||||||
v-for="(theme, key) in themes"
|
v-for="(theme, key) in themeList"
|
||||||
:key="key"
|
:key="key"
|
||||||
v-b-tooltip.hover.right
|
v-b-tooltip.hover.right
|
||||||
:active="activeTheme === theme.name"
|
:active="activeTheme === theme.name"
|
||||||
|
@ -23,129 +24,32 @@
|
||||||
>{{ theme.name }}{{ theme.dark ? ' [dark]' : '' }}</b-dropdown-item-button
|
>{{ theme.name }}{{ theme.dark ? ' [dark]' : '' }}</b-dropdown-item-button
|
||||||
>
|
>
|
||||||
</b-nav-item-dropdown>
|
</b-nav-item-dropdown>
|
||||||
|
<b-link v-else variant="outline-primary" class="nav-link" @click="toggleNight">
|
||||||
|
<ThemeLightDark :size="16" />
|
||||||
|
</b-link>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
|
import Vue from 'vue';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import ThemeLightDark from 'vue-material-design-icons/Brightness6.vue';
|
||||||
|
import { themeList } from '@/shared/themes';
|
||||||
|
import { mapActions } from 'vuex';
|
||||||
|
|
||||||
export default {
|
export default Vue.extend({
|
||||||
name: 'BootswatchThemeSelect',
|
name: 'BootswatchThemeSelect',
|
||||||
|
components: { ThemeLightDark },
|
||||||
|
props: {
|
||||||
|
simple: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
activeTheme: '',
|
activeTheme: '',
|
||||||
themes: [
|
themeList,
|
||||||
{
|
|
||||||
name: 'Bootstrap',
|
|
||||||
description: 'Plain bootstrap default theme',
|
|
||||||
dark: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Cerulean',
|
|
||||||
description: 'A calm blue sky',
|
|
||||||
dark: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Cosmo',
|
|
||||||
description: 'An ode to Metro',
|
|
||||||
dark: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Cyborg',
|
|
||||||
description: 'Jet black and electric blue',
|
|
||||||
dark: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Darkly',
|
|
||||||
description: 'Flatly in night mode',
|
|
||||||
dark: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Flatly',
|
|
||||||
description: 'Flat and modern',
|
|
||||||
dark: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Journal',
|
|
||||||
description: 'Crisp like a new sheet of paper',
|
|
||||||
dark: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Litera',
|
|
||||||
description: 'The medium is the message',
|
|
||||||
dark: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Lumen',
|
|
||||||
description: 'Light and shadow',
|
|
||||||
dark: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Lux',
|
|
||||||
description: 'A touch of class',
|
|
||||||
dark: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Materia',
|
|
||||||
description: 'Material is the metaphor',
|
|
||||||
dark: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Minty',
|
|
||||||
description: 'A fresh feel',
|
|
||||||
dark: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Pulse',
|
|
||||||
description: 'A trace of purple',
|
|
||||||
dark: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Sandstone',
|
|
||||||
description: 'A touch of warmth',
|
|
||||||
dark: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Simplex',
|
|
||||||
description: 'Mini and minimalist',
|
|
||||||
dark: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Sketchy',
|
|
||||||
description: 'A hand-drawn look for mockups and mirth',
|
|
||||||
dark: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Slate',
|
|
||||||
description: 'Shades of gunmetal gray',
|
|
||||||
dark: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Solar',
|
|
||||||
description: 'A spin on Solarized',
|
|
||||||
dark: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Spacelab',
|
|
||||||
description: 'Silvery and sleek',
|
|
||||||
dark: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Superhero',
|
|
||||||
description: 'The brave and the blue',
|
|
||||||
dark: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'United',
|
|
||||||
description: 'Ubuntu orange and unique font',
|
|
||||||
dark: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Yeti',
|
|
||||||
description: 'A friendly foundation',
|
|
||||||
dark: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
@ -153,43 +57,59 @@ export default {
|
||||||
if (window.localStorage.theme) this.setTheme(window.localStorage.theme);
|
if (window.localStorage.theme) this.setTheme(window.localStorage.theme);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
...mapActions(['setCurrentTheme']),
|
||||||
handleClick(e) {
|
handleClick(e) {
|
||||||
this.setTheme(e.target.name.trim());
|
this.setTheme(e.target.name.trim());
|
||||||
},
|
},
|
||||||
|
toggleNight() {
|
||||||
|
this.setTheme(this.activeTheme === 'bootstrap' ? 'bootstrap_dark' : 'bootstrap');
|
||||||
|
},
|
||||||
setTheme(themeName) {
|
setTheme(themeName) {
|
||||||
// If theme is already active, do nothing.
|
// If theme is already active, do nothing.
|
||||||
if (this.activeTheme === themeName) {
|
if (this.activeTheme === themeName) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (themeName.toLowerCase() === 'bootstrap') {
|
if (themeName.toLowerCase() === 'bootstrap' || themeName.toLowerCase() === 'bootstrap_dark') {
|
||||||
const styles = document.getElementsByTagName('style');
|
const styles = document.getElementsByTagName('style');
|
||||||
const bw = Array.from(styles).filter((w) => w.textContent.includes('bootswatch'));
|
const bw = Array.from(styles).filter((w) => w.textContent?.includes('bootswatch'));
|
||||||
|
document.documentElement.setAttribute(
|
||||||
|
'data-theme',
|
||||||
|
themeName.toLowerCase() === 'bootstrap' ? 'light' : 'dark',
|
||||||
|
);
|
||||||
// Reset all bootswatch styles
|
// Reset all bootswatch styles
|
||||||
bw.forEach((style, index) => {
|
bw.forEach((style, index) => {
|
||||||
bw[index].disabled = true;
|
(bw[index] as any).disabled = true;
|
||||||
});
|
});
|
||||||
|
if (this.simple) {
|
||||||
|
// Only transition if simple mode is active
|
||||||
|
document.documentElement.classList.add('ft-theme-transition');
|
||||||
|
window.setTimeout(() => {
|
||||||
|
document.documentElement.classList.remove('ft-theme-transition');
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Dynamic import for a different theme, to avoid loading ALL themes.
|
// Dynamic import for a different theme, to avoid loading ALL themes.
|
||||||
import(`bootswatch/dist/${themeName.toLowerCase()}/bootstrap.min.css`).then((mod) => {
|
import(`bootswatch/dist/${themeName.toLowerCase()}/bootstrap.min.css`).then((mod) => {
|
||||||
console.log('theme', mod);
|
console.log('theme', mod);
|
||||||
|
document.documentElement.removeAttribute('data-theme');
|
||||||
const styles = document.getElementsByTagName('style');
|
const styles = document.getElementsByTagName('style');
|
||||||
const bw = Array.from(styles).filter((w) => w.textContent.includes('bootswatch'));
|
const bw = Array.from(styles).filter((w) => w.textContent?.includes('bootswatch'));
|
||||||
bw.forEach((style, index) => {
|
bw.forEach((style, index) => {
|
||||||
if (!style.id) {
|
if (!style.id) {
|
||||||
// If its a style that was just imported and hasn't been assigned an id.
|
// If its a style that was just imported and hasn't been assigned an id.
|
||||||
bw[index].id = themeName;
|
bw[index].id = themeName;
|
||||||
} else if (style.id === themeName) {
|
} else if (style.id === themeName) {
|
||||||
// If it's a style that has been imported already.
|
// If it's a style that has been imported already.
|
||||||
bw[index].disabled = false;
|
(bw[index] as any).disabled = false;
|
||||||
} else {
|
} else {
|
||||||
// All other style themes should be disabled.
|
// All other style themes should be disabled.
|
||||||
bw[index].disabled = true;
|
(bw[index] as any).disabled = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Save the theme as localstorage
|
// Save the theme as localstorage
|
||||||
window.localStorage.theme = themeName;
|
this.setCurrentTheme(themeName);
|
||||||
this.activeTheme = themeName;
|
this.activeTheme = themeName;
|
||||||
},
|
},
|
||||||
fetchApi() {
|
fetchApi() {
|
||||||
|
@ -197,23 +117,23 @@ export default {
|
||||||
// Not used, but useful for updating the static array of themes if bootswatch dependency is outdated.
|
// Not used, but useful for updating the static array of themes if bootswatch dependency is outdated.
|
||||||
axios
|
axios
|
||||||
.get('https://bootswatch.com/api/4.json')
|
.get('https://bootswatch.com/api/4.json')
|
||||||
.then((res) => {
|
// .then((res) => {
|
||||||
const { themes } = res.data;
|
|
||||||
this.themes = themes;
|
|
||||||
|
|
||||||
// Use this code in the browser console and copy and paste the filteredThemes into this.themes
|
// const { themes } = res.data;
|
||||||
// console.log(themes);
|
// this.themes = themes;
|
||||||
// const filteredThemes = [];
|
// Use this code in the browser console and copy and paste the filteredThemes into this.themes
|
||||||
// themes.forEach((item) =>
|
// console.log(themes);
|
||||||
// filteredThemes.push({ name: item.name, description: item.description }),
|
// const filteredThemes = [];
|
||||||
// );
|
// themes.forEach((item) =>
|
||||||
})
|
// filteredThemes.push({ name: item.name, description: item.description }),
|
||||||
|
// );
|
||||||
|
// })
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="row flex-grow-1 chart-wrapper">
|
<div class="row flex-grow-1 chart-wrapper">
|
||||||
<v-chart v-if="hasData" theme="dark" autoresize :options="chartOptions" />
|
<v-chart v-if="hasData" :theme="theme" autoresize :options="chartOptions" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -41,6 +41,8 @@ export default class CandleChart extends Vue {
|
||||||
|
|
||||||
@Prop({ required: true }) plotConfig!: PlotConfig;
|
@Prop({ required: true }) plotConfig!: PlotConfig;
|
||||||
|
|
||||||
|
@Prop({ default: 'dark' }) theme!: string;
|
||||||
|
|
||||||
buyData = [] as Array<number>[];
|
buyData = [] as Array<number>[];
|
||||||
|
|
||||||
sellData = [] as Array<number>[];
|
sellData = [] as Array<number>[];
|
||||||
|
@ -95,7 +97,7 @@ export default class CandleChart extends Vue {
|
||||||
text: `${this.strategy} - ${this.pair} - ${this.timeframe}`,
|
text: `${this.strategy} - ${this.pair} - ${this.timeframe}`,
|
||||||
show: true,
|
show: true,
|
||||||
},
|
},
|
||||||
backgroundColor: '#1b1b1b',
|
// backgroundColor: '#1b1b1b',
|
||||||
useUTC: this.useUTC,
|
useUTC: this.useUTC,
|
||||||
animation: false,
|
animation: false,
|
||||||
legend: {
|
legend: {
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
:trades="trades"
|
:trades="trades"
|
||||||
:plot-config="plotConfig"
|
:plot-config="plotConfig"
|
||||||
:use-u-t-c="useUTC"
|
:use-u-t-c="useUTC"
|
||||||
|
:theme="getChartTheme"
|
||||||
>
|
>
|
||||||
</CandleChart>
|
</CandleChart>
|
||||||
<label v-else style="margin: auto auto; font-size: 1.5rem">No data available</label>
|
<label v-else style="margin: auto auto; font-size: 1.5rem">No data available</label>
|
||||||
|
@ -54,7 +55,7 @@
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Component, Vue, Prop, Watch } from 'vue-property-decorator';
|
import { Component, Vue, Prop, Watch } from 'vue-property-decorator';
|
||||||
import { namespace } from 'vuex-class';
|
import { Getter, namespace } from 'vuex-class';
|
||||||
import {
|
import {
|
||||||
Trade,
|
Trade,
|
||||||
PairHistory,
|
PairHistory,
|
||||||
|
@ -96,6 +97,8 @@ export default class CandleChartContainer extends Vue {
|
||||||
|
|
||||||
plotConfigName = '';
|
plotConfigName = '';
|
||||||
|
|
||||||
|
@Getter getChartTheme!: string;
|
||||||
|
|
||||||
@ftbot.State availablePlotConfigNames!: Array<string>;
|
@ftbot.State availablePlotConfigNames!: Array<string>;
|
||||||
|
|
||||||
@ftbot.Action setPlotConfigName;
|
@ftbot.Action setPlotConfigName;
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<v-chart v-if="trades.length > 0" :options="chartOptions" autoresize />
|
<v-chart v-if="trades.length > 0" :options="chartOptions" autoresize :theme="getChartTheme" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Component, Vue, Prop } from 'vue-property-decorator';
|
import { Component, Vue, Prop } from 'vue-property-decorator';
|
||||||
|
import { Getter } from 'vuex-class';
|
||||||
|
|
||||||
import ECharts from 'vue-echarts';
|
import ECharts from 'vue-echarts';
|
||||||
import { EChartOption } from 'echarts';
|
import { EChartOption } from 'echarts';
|
||||||
|
@ -35,6 +36,8 @@ export default class CumProfitChart extends Vue {
|
||||||
|
|
||||||
@Prop({ default: 'close_profit_abs' }) profitColumn!: string;
|
@Prop({ default: 'close_profit_abs' }) profitColumn!: string;
|
||||||
|
|
||||||
|
@Getter getChartTheme!: string;
|
||||||
|
|
||||||
get cumulativeData() {
|
get cumulativeData() {
|
||||||
const res: CumProfitData[] = [];
|
const res: CumProfitData[] = [];
|
||||||
const closedTrades = this.trades; // .filter((t) => t.close_timestamp);
|
const closedTrades = this.trades; // .filter((t) => t.close_timestamp);
|
||||||
|
@ -122,10 +125,10 @@ export default class CumProfitChart extends Vue {
|
||||||
name: CHART_PROFIT,
|
name: CHART_PROFIT,
|
||||||
animation: false,
|
animation: false,
|
||||||
lineStyle: {
|
lineStyle: {
|
||||||
color: 'black',
|
color: this.getChartTheme === 'dark' ? '#c2c2c2' : 'black',
|
||||||
},
|
},
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
color: 'black',
|
color: this.getChartTheme === 'dark' ? '#c2c2c2' : 'black',
|
||||||
},
|
},
|
||||||
// symbol: 'none',
|
// symbol: 'none',
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<v-chart v-if="dailyStats.data" :options="dailyChartOptions" autoresize />
|
<v-chart v-if="dailyStats.data" :options="dailyChartOptions" :theme="getChartTheme" autoresize />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Component, Vue, Prop } from 'vue-property-decorator';
|
import { Component, Vue, Prop } from 'vue-property-decorator';
|
||||||
|
import { Getter } from 'vuex-class';
|
||||||
import ECharts from 'vue-echarts';
|
import ECharts from 'vue-echarts';
|
||||||
import { EChartOption } from 'echarts';
|
import { EChartOption } from 'echarts';
|
||||||
|
|
||||||
|
@ -30,6 +30,8 @@ export default class DailyChart extends Vue {
|
||||||
|
|
||||||
@Prop({ default: true, type: Boolean }) showTitle!: boolean;
|
@Prop({ default: true, type: Boolean }) showTitle!: boolean;
|
||||||
|
|
||||||
|
@Getter getChartTheme!: string;
|
||||||
|
|
||||||
get absoluteMin() {
|
get absoluteMin() {
|
||||||
return Number(
|
return Number(
|
||||||
this.dailyStats.data.reduce(
|
this.dailyStats.data.reduce(
|
||||||
|
|
|
@ -1,9 +1,15 @@
|
||||||
<template>
|
<template>
|
||||||
<v-chart v-if="trades.length > 0" :options="hourlyChartOptions" autoresize />
|
<v-chart
|
||||||
|
v-if="trades.length > 0"
|
||||||
|
:options="hourlyChartOptions"
|
||||||
|
autoresize
|
||||||
|
:theme="getChartTheme"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Component, Vue, Prop } from 'vue-property-decorator';
|
import { Component, Vue, Prop } from 'vue-property-decorator';
|
||||||
|
import { Getter } from 'vuex-class';
|
||||||
|
|
||||||
import ECharts from 'vue-echarts';
|
import ECharts from 'vue-echarts';
|
||||||
|
|
||||||
|
@ -33,6 +39,8 @@ export default class HourlyChart extends Vue {
|
||||||
|
|
||||||
@Prop({ default: true, type: Boolean }) showTitle!: boolean;
|
@Prop({ default: true, type: Boolean }) showTitle!: boolean;
|
||||||
|
|
||||||
|
@Getter getChartTheme!: string;
|
||||||
|
|
||||||
get hourlyData() {
|
get hourlyData() {
|
||||||
const res = new Array(24);
|
const res = new Array(24);
|
||||||
for (let i = 0; i < 24; i += 1) {
|
for (let i = 0; i < 24; i += 1) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<b-navbar toggleable="lg" type="dark" variant="info">
|
<b-navbar toggleable="lg" type="dark" variant="primary">
|
||||||
<b-navbar-brand exact to="/">
|
<b-navbar-brand exact to="/">
|
||||||
<img class="logo" src="@/assets/freqtrade-logo.png" alt="Home Logo" />
|
<img class="logo" src="@/assets/freqtrade-logo.png" alt="Home Logo" />
|
||||||
<span class="navbar-brand-title">Freqtrade UI</span>
|
<span class="navbar-brand-title">Freqtrade UI</span>
|
||||||
|
@ -123,6 +123,7 @@ export default class NavBar extends Vue {
|
||||||
.nav-link:active {
|
.nav-link:active {
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.verticalCenter {
|
.verticalCenter {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
|
|
181
src/shared/themes.ts
Normal file
181
src/shared/themes.ts
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
export interface ThemeType {
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
dark: boolean;
|
||||||
|
bootswatch: boolean;
|
||||||
|
}
|
||||||
|
export const themeList: ThemeType[] = [
|
||||||
|
{
|
||||||
|
name: 'Bootstrap',
|
||||||
|
description: 'Plain bootstrap default theme',
|
||||||
|
dark: false,
|
||||||
|
bootswatch: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Bootstrap_dark',
|
||||||
|
description: 'Plain dark bootstrap default theme',
|
||||||
|
dark: true,
|
||||||
|
bootswatch: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Cerulean',
|
||||||
|
description: 'A calm blue sky',
|
||||||
|
dark: false,
|
||||||
|
bootswatch: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Cosmo',
|
||||||
|
description: 'An ode to Metro',
|
||||||
|
dark: false,
|
||||||
|
bootswatch: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'Cyborg',
|
||||||
|
description: 'Jet black and electric blue',
|
||||||
|
dark: true,
|
||||||
|
bootswatch: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'Darkly',
|
||||||
|
description: 'Flatly in night mode',
|
||||||
|
dark: true,
|
||||||
|
bootswatch: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'Flatly',
|
||||||
|
description: 'Flat and modern',
|
||||||
|
dark: false,
|
||||||
|
bootswatch: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'Journal',
|
||||||
|
description: 'Crisp like a new sheet of paper',
|
||||||
|
dark: false,
|
||||||
|
bootswatch: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'Litera',
|
||||||
|
description: 'The medium is the message',
|
||||||
|
dark: false,
|
||||||
|
bootswatch: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'Lumen',
|
||||||
|
description: 'Light and shadow',
|
||||||
|
dark: false,
|
||||||
|
bootswatch: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'Lux',
|
||||||
|
description: 'A touch of class',
|
||||||
|
dark: false,
|
||||||
|
bootswatch: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'Materia',
|
||||||
|
description: 'Material is the metaphor',
|
||||||
|
dark: false,
|
||||||
|
bootswatch: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'Minty',
|
||||||
|
description: 'A fresh feel',
|
||||||
|
dark: false,
|
||||||
|
bootswatch: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'Pulse',
|
||||||
|
description: 'A trace of purple',
|
||||||
|
dark: false,
|
||||||
|
bootswatch: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'Sandstone',
|
||||||
|
description: 'A touch of warmth',
|
||||||
|
dark: false,
|
||||||
|
bootswatch: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'Simplex',
|
||||||
|
description: 'Mini and minimalist',
|
||||||
|
dark: false,
|
||||||
|
bootswatch: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'Sketchy',
|
||||||
|
description: 'A hand-drawn look for mockups and mirth',
|
||||||
|
dark: false,
|
||||||
|
bootswatch: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'Slate',
|
||||||
|
description: 'Shades of gunmetal gray',
|
||||||
|
dark: true,
|
||||||
|
bootswatch: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'Solar',
|
||||||
|
description: 'A spin on Solarized',
|
||||||
|
dark: true,
|
||||||
|
bootswatch: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'Spacelab',
|
||||||
|
description: 'Silvery and sleek',
|
||||||
|
dark: false,
|
||||||
|
bootswatch: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'Superhero',
|
||||||
|
description: 'The brave and the blue',
|
||||||
|
dark: true,
|
||||||
|
bootswatch: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'United',
|
||||||
|
description: 'Ubuntu orange and unique font',
|
||||||
|
dark: false,
|
||||||
|
bootswatch: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'Yeti',
|
||||||
|
description: 'A friendly foundation',
|
||||||
|
dark: false,
|
||||||
|
bootswatch: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export function storeCurrentTheme(themeName: string) {
|
||||||
|
window.localStorage.theme = themeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTheme(theme: string): ThemeType | undefined {
|
||||||
|
if (theme !== undefined) {
|
||||||
|
return themeList.find((item) => item.name.toLowerCase() === theme.toLowerCase());
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCurrentTheme(): string {
|
||||||
|
const { theme } = window.localStorage;
|
||||||
|
return theme;
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ import Vue from 'vue';
|
||||||
import Vuex from 'vuex';
|
import Vuex from 'vuex';
|
||||||
|
|
||||||
import userService from '@/shared/userService';
|
import userService from '@/shared/userService';
|
||||||
|
import { getCurrentTheme, getTheme, storeCurrentTheme } from '@/shared/themes';
|
||||||
import ftbotModule, { BotStoreGetters } from './modules/ftbot';
|
import ftbotModule, { BotStoreGetters } from './modules/ftbot';
|
||||||
import alertsModule from './modules/alerts';
|
import alertsModule from './modules/alerts';
|
||||||
import layoutModule from './modules/layout';
|
import layoutModule from './modules/layout';
|
||||||
|
@ -9,6 +10,7 @@ import layoutModule from './modules/layout';
|
||||||
const AUTO_REFRESH = 'ft_auto_refresh';
|
const AUTO_REFRESH = 'ft_auto_refresh';
|
||||||
|
|
||||||
Vue.use(Vuex);
|
Vue.use(Vuex);
|
||||||
|
const initCurrentTheme = getCurrentTheme();
|
||||||
|
|
||||||
export default new Vuex.Store({
|
export default new Vuex.Store({
|
||||||
state: {
|
state: {
|
||||||
|
@ -16,6 +18,19 @@ export default new Vuex.Store({
|
||||||
loggedIn: userService.loggedIn(),
|
loggedIn: userService.loggedIn(),
|
||||||
autoRefresh: JSON.parse(localStorage.getItem(AUTO_REFRESH) || '{}'),
|
autoRefresh: JSON.parse(localStorage.getItem(AUTO_REFRESH) || '{}'),
|
||||||
isBotOnline: false,
|
isBotOnline: false,
|
||||||
|
currentTheme: initCurrentTheme,
|
||||||
|
},
|
||||||
|
getters: {
|
||||||
|
isDarkTheme(state) {
|
||||||
|
const theme = getTheme(state.currentTheme);
|
||||||
|
if (theme) {
|
||||||
|
return theme.dark;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
getChartTheme(state, getters) {
|
||||||
|
return getters.isDarkTheme ? 'dark' : 'light';
|
||||||
|
},
|
||||||
},
|
},
|
||||||
modules: {
|
modules: {
|
||||||
ftbot: ftbotModule,
|
ftbot: ftbotModule,
|
||||||
|
@ -37,8 +52,15 @@ export default new Vuex.Store({
|
||||||
setIsBotOnline(state, isBotOnline: boolean) {
|
setIsBotOnline(state, isBotOnline: boolean) {
|
||||||
state.isBotOnline = isBotOnline;
|
state.isBotOnline = isBotOnline;
|
||||||
},
|
},
|
||||||
|
mutateCurrentTheme(state, newTheme: string) {
|
||||||
|
storeCurrentTheme(newTheme);
|
||||||
|
state.currentTheme = newTheme;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
|
setCurrentTheme({ commit }, newTheme: string) {
|
||||||
|
commit('mutateCurrentTheme', newTheme);
|
||||||
|
},
|
||||||
setAutoRefresh({ commit }, newRefreshValue) {
|
setAutoRefresh({ commit }, newRefreshValue) {
|
||||||
commit('setAutoRefresh', newRefreshValue);
|
commit('setAutoRefresh', newRefreshValue);
|
||||||
localStorage.setItem(AUTO_REFRESH, JSON.stringify(newRefreshValue));
|
localStorage.setItem(AUTO_REFRESH, JSON.stringify(newRefreshValue));
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
// Overwrite bootstrap scss variables
|
// Overwrite bootstrap scss variables
|
||||||
// $body-bg: rgb(42, 42, 49);
|
// $body-bg: rgb(42, 42, 49);
|
||||||
$font-size-base: 0.9rem;
|
$font-size-base: 0.9rem;
|
||||||
|
$primary: #0089a1;
|
||||||
|
|
|
@ -1,5 +1,91 @@
|
||||||
// global main style
|
// global main style
|
||||||
|
|
||||||
// html, body, #app{
|
.logo-svg {
|
||||||
|
background-color: #000000;
|
||||||
|
}
|
||||||
|
|
||||||
// }
|
[data-theme="dark"] {
|
||||||
|
$bg-dark: #3c3c3c;
|
||||||
|
$bg-darker: darken($bg-dark, 5%);
|
||||||
|
$fg-color: #dedede;
|
||||||
|
|
||||||
|
background-color: darken($bg-dark, 5%) ;
|
||||||
|
color: $fg-color !important;
|
||||||
|
body {
|
||||||
|
background: $bg-darker;
|
||||||
|
color: $fg-color;
|
||||||
|
}
|
||||||
|
.card {
|
||||||
|
border-color: lighten($bg-dark, 10%);
|
||||||
|
}
|
||||||
|
.card-body {
|
||||||
|
background: $bg-dark;
|
||||||
|
color: $fg-color;
|
||||||
|
}
|
||||||
|
.card-header {
|
||||||
|
background: lighten($bg-dark, 5%);
|
||||||
|
color: $fg-color;
|
||||||
|
}
|
||||||
|
.table {
|
||||||
|
color: $fg-color;
|
||||||
|
}
|
||||||
|
.list-group-item {
|
||||||
|
color: $fg-color;
|
||||||
|
background: $bg-dark;
|
||||||
|
}
|
||||||
|
// .custom-select {
|
||||||
|
// color: $fg-color;
|
||||||
|
// // background: $bg-dark;
|
||||||
|
// }
|
||||||
|
.nav-tabs {
|
||||||
|
border-bottom: 1px solid lighten($bg-dark, 20%);
|
||||||
|
.nav-link
|
||||||
|
{
|
||||||
|
color: $primary;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: lighten($bg-dark, 5%);
|
||||||
|
color: lighten($primary, 10%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.nav-link.active {
|
||||||
|
color: $fg-color;
|
||||||
|
background: $bg-darker;
|
||||||
|
border-color: lighten($bg-dark, 20%);
|
||||||
|
}
|
||||||
|
.modal-content {
|
||||||
|
color: $fg-color;
|
||||||
|
background: $bg-dark;
|
||||||
|
}
|
||||||
|
.form-control {
|
||||||
|
color: $fg-color;
|
||||||
|
background: $bg-dark;
|
||||||
|
}
|
||||||
|
.popover {
|
||||||
|
background: $bg-dark;
|
||||||
|
}
|
||||||
|
.popover-body {
|
||||||
|
color: $fg-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-svg {
|
||||||
|
background-color: $fg-color;
|
||||||
|
}
|
||||||
|
textarea {
|
||||||
|
color: $fg-color;
|
||||||
|
background: $bg-dark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
html.ft-theme-transition,
|
||||||
|
html.ft-theme-transition *,
|
||||||
|
html.ft-theme-transition *:before,
|
||||||
|
html.ft-theme-transition *:after {
|
||||||
|
transition:background 750ms ease-in-out,
|
||||||
|
border-color 750ms ease-in-out;
|
||||||
|
transition-delay: 0 !important;
|
||||||
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
|
|
||||||
@import '_bootstrap_variables_ovw.scss';
|
@import 'bootstrap_variables_ovw';
|
||||||
|
|
||||||
@import '~bootstrap/scss/bootstrap.scss';
|
@import '~bootstrap/scss/bootstrap';
|
||||||
@import '~bootstrap-vue/src/index.scss';
|
@import '~bootstrap-vue/src/index';
|
||||||
|
|
||||||
@import 'variables';
|
@import 'variables';
|
||||||
@import 'styles_ovw';
|
@import 'styles_ovw';
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
<b-card header="Open / Total trades">
|
<b-card header="Open / Total trades">
|
||||||
<b-card-text>
|
<b-card-text>
|
||||||
<span class="text-primary">{{ openTrades.length }}</span> /
|
<span class="text-primary">{{ openTrades.length }}</span> /
|
||||||
<span class="text-secondary">{{ profit.trade_count }}</span>
|
<span class="text">{{ profit.trade_count }}</span>
|
||||||
</b-card-text>
|
</b-card-text>
|
||||||
</b-card>
|
</b-card>
|
||||||
<b-card header="Won / lost trades">
|
<b-card header="Won / lost trades">
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="home">
|
<div class="home">
|
||||||
<img alt="Freqtrade logo" src="../assets/freqtrade-logo.png" />
|
<!-- <img alt="Freqtrade logo" src="../assets/freqtrade-logo.png" width="450px" class="my-5" /> -->
|
||||||
|
<div alt="Freqtrade logo" class="logo-svg my-5 mx-auto" />
|
||||||
<div>
|
<div>
|
||||||
<h1>Welcome to the Freqtrade UI</h1>
|
<h1>Welcome to the Freqtrade UI</h1>
|
||||||
</div>
|
</div>
|
||||||
|
@ -26,4 +27,11 @@ export default class Home extends Vue {}
|
||||||
.home {
|
.home {
|
||||||
margin-top: 1.5em;
|
margin-top: 1.5em;
|
||||||
}
|
}
|
||||||
|
.logo-svg {
|
||||||
|
-webkit-mask: url(../assets/freqtrade-logo-mask.png) no-repeat center;
|
||||||
|
mask: url(../assets/freqtrade-logo-mask.png) no-repeat center;
|
||||||
|
mask-size: contain;
|
||||||
|
width: 250px;
|
||||||
|
height: 250px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user