diff --git a/src/components/mixins/ChartSpecMixin.ts b/src/components/mixins/ChartSpecMixin.ts index 7c9121aa8..793b83fe7 100644 --- a/src/components/mixins/ChartSpecMixin.ts +++ b/src/components/mixins/ChartSpecMixin.ts @@ -62,18 +62,18 @@ export default class ChartSpecMixin extends Mixins(ThemePaletteMixin, Translatio fontWeight: 'bold', }, }, - color: this.theme.color.base.content.secondary, + color: this.chartTheme.color.base.content.secondary, offset: AXIS_OFFSET, ...AXIS_LABEL_CSS, }, axisPointer: { lineStyle: { - color: this.theme.color.status.success, + color: this.chartTheme.color.status.success, }, label: { show: true, - backgroundColor: this.theme.color.status.success, - color: this.theme.color.base.onAccent, + backgroundColor: this.chartTheme.color.status.success, + color: this.chartTheme.color.base.onAccent, fontSize: 11, fontWeight: 400, lineHeigth: 1.5, @@ -99,24 +99,24 @@ export default class ChartSpecMixin extends Mixins(ThemePaletteMixin, Translatio }, axisLine: { lineStyle: { - color: this.theme.color.base.content.secondary, + color: this.chartTheme.color.base.content.secondary, }, }, axisPointer: { lineStyle: { - color: this.theme.color.status.success, + color: this.chartTheme.color.status.success, }, label: { ...AXIS_LABEL_CSS, - backgroundColor: this.theme.color.status.success, + backgroundColor: this.chartTheme.color.status.success, fontWeight: 400, padding: [LABEL_PADDING, LABEL_PADDING], - color: this.theme.color.base.onAccent, + color: this.chartTheme.color.base.onAccent, }, }, splitLine: { lineStyle: { - color: this.theme.color.base.content.tertiary, + color: this.chartTheme.color.base.content.tertiary, opacity: 0.2, }, }, @@ -127,11 +127,11 @@ export default class ChartSpecMixin extends Mixins(ThemePaletteMixin, Translatio return merge({ show: true, trigger: 'axis', - backgroundColor: this.theme.color.utility.body, - borderColor: this.theme.color.base.border.secondary, - extraCssText: `box-shadow: ${this.theme.shadow.dialog}; border-radius: ${this.theme.border.radius.mini}`, + backgroundColor: this.chartTheme.color.utility.body, + borderColor: this.chartTheme.color.base.border.secondary, + extraCssText: `box-shadow: ${this.chartTheme.shadow.dialog}; border-radius: ${this.chartTheme.border.radius.mini}`, textStyle: { - color: this.theme.color.base.content.secondary, + color: this.chartTheme.color.base.content.secondary, fontSize: 11, fontFamily: 'Sora', fontWeight: 400, @@ -146,7 +146,7 @@ export default class ChartSpecMixin extends Mixins(ThemePaletteMixin, Translatio }, showSymbol: false, itemStyle: { - color: this.theme.color.theme.accent, + color: this.chartTheme.color.theme.accent, }, })(options); } @@ -159,7 +159,7 @@ export default class ChartSpecMixin extends Mixins(ThemePaletteMixin, Translatio }, showSymbol: false, itemStyle: { - color: this.theme.color.theme.accent, + color: this.chartTheme.color.theme.accent, }, })(options); } @@ -172,7 +172,7 @@ export default class ChartSpecMixin extends Mixins(ThemePaletteMixin, Translatio }, showSymbol: false, itemStyle: { - color: this.theme.color.theme.accent, + color: this.chartTheme.color.theme.accent, }, })(options); } @@ -182,10 +182,10 @@ export default class ChartSpecMixin extends Mixins(ThemePaletteMixin, Translatio type: 'candlestick', barMaxWidth: 10, itemStyle: { - color: this.theme.color.status.success, - borderColor: this.theme.color.status.success, - color0: this.theme.color.theme.accentHover, - borderColor0: this.theme.color.theme.accentHover, + color: this.chartTheme.color.status.success, + borderColor: this.chartTheme.color.status.success, + color0: this.chartTheme.color.theme.accentHover, + borderColor0: this.chartTheme.color.theme.accentHover, borderWidth: 2, }, })(options); diff --git a/src/components/mixins/ThemePaletteMixin.ts b/src/components/mixins/ThemePaletteMixin.ts index 58ca87f39..30e7ac282 100644 --- a/src/components/mixins/ThemePaletteMixin.ts +++ b/src/components/mixins/ThemePaletteMixin.ts @@ -1,16 +1,36 @@ +import Theme from '@soramitsu-ui/ui-vue2/lib/types/Theme'; import { Component, Vue } from 'vue-property-decorator'; -import { getter } from '@/store/decorators'; +import type { Color, ColorDirection, ColorType, DirectionType } from '@/consts/color'; +import { state, getter } from '@/store/decorators'; import { getCssVariableValue as css } from '@/utils'; -import type Theme from '@soramitsu-ui/ui-vue2/lib/types/Theme'; +import store from '../../store'; @Component export default class ThemePaletteMixin extends Vue { + @state.settings.colorType colorType!: ColorType; @getter.libraryTheme libraryTheme!: Theme; - get theme() { + get color(): ColorType { + return store.state.settings.colorType; + } + + set color(value: ColorType) { + store.commit.settings.setColorType(value); + } + + get direction(): DirectionType { + return store.state.settings.colorDirection; + } + + set direction(value: DirectionType) { + store.commit.settings.setColorDirection(value); + } + + get chartTheme() { const libraryTheme = this.libraryTheme; + const currentColor = this.getColorPalette(); const palette = { color: { @@ -33,8 +53,8 @@ export default class ThemePaletteMixin extends Vue { body: css('--s-color-utility-body'), }, status: { - success: css('--s-color-status-success'), - error: css('--s-color-status-error'), + success: currentColor.side.buy, + error: currentColor.side.sell, warning: css('--s-color-status-warning'), info: css('--s-color-status-info'), }, @@ -51,4 +71,81 @@ export default class ThemePaletteMixin extends Vue { return !!libraryTheme && palette; } + + isInversed = (value: boolean): boolean => { + const direction = this.getColorDirection(); + + return direction.type === 'classic' ? value : !value; + }; + + colors = (type?: ColorType, theme = Theme.LIGHT): any => { + const palette = { + classic: { + name: 'Classic', + type: 'classic', + side: { buy: css('--s-color-classic-up'), sell: css('--s-color-classic-down') }, + priceChange: { up: css('--s-color-classic-price-change-up'), down: css('--s-color-classic-price-change-down') }, + bookBars: { + buy: theme === Theme.LIGHT ? css('--s-color-classic-bar-light-buy') : css('--s-color-classic-bar-dark-buy'), + sell: + theme === Theme.LIGHT ? css('--s-color-classic-bar-light-sell') : css('--s-color-classic-bar-dark-sell'), + }, + }, + deficiency: { + name: 'Color deficiency', + type: 'deficiency', + side: { buy: css('--s-color-deficiency-up'), sell: css('--s-color-deficiency-down') }, + priceChange: { + up: css('--s-color-deficiency-price-change-up'), + down: css('--s-color-deficiency-price-change-down'), + }, + bookBars: { + buy: + theme === Theme.LIGHT + ? css('--s-color-deficiency-bar-light-buy') + : css('--s-color-deficiency-bar-dark-buy'), + sell: + theme === Theme.LIGHT + ? css('--s-color-deficiency-bar-light-sell') + : css('--s-color-deficiency-bar-dark-sell'), + }, + }, + traditional: { + name: 'Traditional', + type: 'traditional', + side: { buy: css('--s-color-traditional-up'), sell: css('--s-color-traditional-down') }, + priceChange: { + up: css('--s-color-traditional-price-change-up'), + down: css('--s-color-tradtional-price-change-down'), + }, + bookBars: { + buy: + theme === Theme.LIGHT + ? css('--s-color-traditional-bar-light-buy') + : css('--s-color-traditional-bar-dark-buy'), + sell: + theme === Theme.LIGHT + ? css('--s-color-traditional-bar-light-sell') + : css('--s-color-traditional-bar-dark-sell'), + }, + }, + }; + + if (!type) return palette; + + return palette[type]; + }; + + directions: Record = { + classic: { name: 'Green Up / Red down', type: 'classic' }, + inverse: { name: 'Green down / Red up', type: 'inverse' }, + }; + + getColorDirection = (type?: DirectionType): ColorDirection => { + return type ? this.directions[type] : this.directions[this.direction]; + }; + + getColorPalette = (type?: ColorType, theme = Theme.LIGHT): Color => { + return type ? this.colors(type, theme) : this.colors(this.color, theme); + }; } diff --git a/src/components/pages/OrderBook/BookWidget.vue b/src/components/pages/OrderBook/BookWidget.vue index 9f929cf9b..a1e5c2c6d 100644 --- a/src/components/pages/OrderBook/BookWidget.vue +++ b/src/components/pages/OrderBook/BookWidget.vue @@ -38,15 +38,15 @@ > {{ order.total }} {{ order.amount }} - {{ order.price }} -
+ {{ order.price }} +
{{ t('orderBook.book.noAsks') }}
-
+
- {{ lastPriceFormatted }} - + {{ lastPriceFormatted }} + {{ fiatValue }}
@@ -54,8 +54,8 @@
{{ order.total }} {{ order.amount }} - {{ order.price }} -
+ {{ order.price }} +
{{ t('orderBook.book.noBids') }}
@@ -68,6 +68,7 @@ import { FPNumber } from '@sora-substrate/util'; import { mixins } from '@soramitsu/soraneo-wallet-web'; import { Component, Mixins, Watch } from 'vue-property-decorator'; +import ThemePaletteMixin from '@/components/mixins/ThemePaletteMixin'; import TranslationMixin from '@/components/mixins/TranslationMixin'; import { Components, LimitOrderType, ZeroStringValue } from '@/consts'; import { lazyComponent } from '@/router'; @@ -91,7 +92,12 @@ type OrderBookPriceVolumeAggregated = [FPNumber, FPNumber, FPNumber]; BaseWidget: lazyComponent(Components.BaseWidget), }, }) -export default class BookWidget extends Mixins(TranslationMixin, mixins.LoadingMixin, mixins.FormattedAmountMixin) { +export default class BookWidget extends Mixins( + TranslationMixin, + ThemePaletteMixin, + mixins.LoadingMixin, + mixins.FormattedAmountMixin +) { @state.orderBook.limitOrderType private limitOrderType!: LimitOrderType; @state.orderBook.asks asks!: OrderBookPriceVolume[]; @state.orderBook.bids bids!: OrderBookPriceVolume[]; @@ -138,7 +144,7 @@ export default class BookWidget extends Mixins(TranslationMixin, mixins.LoadingM return; } this.setSide(side); - this.setQuoteValue(Number(price).toString()); // TODO: [Rustem] string->number->string -- WHY? + this.setQuoteValue(price); } get isMarketOrder(): boolean { @@ -226,10 +232,38 @@ export default class BookWidget extends Mixins(TranslationMixin, mixins.LoadingM return fiat ? `$${fiat}` : ''; } + getFontColor(side: PriceVariant): string { + const theme = this.getColorPalette(); + const color = this.isInversed(side === PriceVariant.Buy) ? theme.side.buy : theme.side.sell; + + return `color: ${color}`; + } + + getStyles(filled: number | undefined, side: PriceVariant): string { + const theme = this.getColorPalette(undefined, this.libraryTheme); + + let color; + + if (theme.bookBars) { + color = this.isInversed(side === PriceVariant.Buy) ? theme.bookBars?.buy : theme.bookBars?.sell; + } else { + color = this.isInversed(side === PriceVariant.Buy) ? theme.side?.buy : theme.side?.sell; + } + + return `width: ${filled}%; background-color: ${color};`; + } + + getMarkedPriceStyles(): string { + const theme = this.getColorPalette(); + const color = this.isInversed(this.lastDealTrendsUp) ? theme.side.buy : theme.side.sell; + + return `color: ${color}`; + } + getComputedClassTrend(): string { const base = ['stock-book-delimiter']; - if (this.lastDealTrendsUp) { + if (this.isInversed(this.lastDealTrendsUp)) { base.push('stock-book-delimiter--up'); } else { base.push('stock-book-delimiter--down'); @@ -259,10 +293,6 @@ export default class BookWidget extends Mixins(TranslationMixin, mixins.LoadingM return `height: ${24 * margin}px`; } - getStyles(filled: number | undefined): string { - return `width: ${filled}%`; - } - isBookPrecisionEqual(precision: string): boolean { return precision === this.currentOrderBook?.tickSize?.toString(); } @@ -280,7 +310,9 @@ export default class BookWidget extends Mixins(TranslationMixin, mixins.LoadingM } /** - * // TODO: [Rustem] add missed type, add missed docs, it's unclear how this method works + * Aggregates orders based on selected precision by user + * @param orders to be aggregated + * @returns aggregated orders */ private calculateStepsDistribution(orders, precision = 10): OrderBookPriceVolumeAggregated[] { return orders; @@ -314,12 +346,12 @@ export default class BookWidget extends Mixins(TranslationMixin, mixins.LoadingM const maxAmount = FPNumber.max(...aggregated.map((order) => order[1])) as FPNumber; const result: LimitOrderForm[] = []; - aggregated.forEach((row: OrderBookPriceVolumeAggregated) => { + aggregated.forEach((row: OrderBookPriceVolume | OrderBookPriceVolumeAggregated) => { const [price, amount, acc] = row; if (amount.isZero()) return; - const total = this.isBookPrecisionEqual(this.selectedStep) ? price.mul(amount) : acc; + const total = (this.isBookPrecisionEqual(this.selectedStep) ? price.mul(amount) : acc) as FPNumber; result.push({ price: this.toBookPrecision(price), @@ -402,26 +434,6 @@ $mono-font: 'JetBrainsMono'; } } - &-buy { - .bar { - background: rgba(185, 235, 219, 0.4); - } - - .order-info.price { - color: var(--status-day-success, #34ad87); - } - } - - &-sell { - .bar { - background: rgba(255, 216, 235, 0.8); - } - - .order-info.price { - color: var(--status-day-error, #f754a3); - } - } - &-delimiter { display: flex; align-items: center; @@ -444,20 +456,6 @@ $mono-font: 'JetBrainsMono'; .trend-icon { margin-left: 4px; } - - &--up { - .mark-price, - .trend-icon { - color: #34ad87; - } - } - - &--down { - .mark-price, - .trend-icon { - color: #f754a3; - } - } } .book-columns { @@ -491,21 +489,5 @@ $mono-font: 'JetBrainsMono'; .book-columns { background-color: #693d81; } - - .stock-book { - &-sell { - .bar { - background-color: rgba(255, 0, 124, 0.3); - } - } - &-buy { - .bar { - background-color: rgba(1, 202, 139, 0.2); - } - } - &-delimiter { - background-color: $background-column-color-dark; - } - } } diff --git a/src/components/pages/OrderBook/BuySell.vue b/src/components/pages/OrderBook/BuySell.vue index 2db70e48f..5fdb60556 100644 --- a/src/components/pages/OrderBook/BuySell.vue +++ b/src/components/pages/OrderBook/BuySell.vue @@ -117,7 +117,6 @@ slot="reference" type="primary" class="btn s-typography-button--medium" - :class="computedBtnClass" @click="placeLimitOrder" :disabled="buttonDisabled" > @@ -160,7 +159,7 @@ slot="reference" type="primary" class="btn s-typography-button--medium" - :class="computedBtnClass" + :style="getColor()" @click="placeLimitOrder" > @@ -39,6 +39,7 @@ import { PriceVariant } from '@sora-substrate/liquidity-proxy'; import dayjs from 'dayjs'; import { Component, Mixins } from 'vue-property-decorator'; +import ThemePaletteMixin from '@/components/mixins/ThemePaletteMixin'; import TranslationMixin from '@/components/mixins/TranslationMixin'; import { Components } from '@/consts'; import { lazyComponent } from '@/router'; @@ -52,7 +53,7 @@ import type { AccountAsset } from '@sora-substrate/util/build/assets/types'; BaseWidget: lazyComponent(Components.BaseWidget), }, }) -export default class MarketTradesWidget extends Mixins(TranslationMixin) { +export default class MarketTradesWidget extends Mixins(TranslationMixin, ThemePaletteMixin) { readonly PriceVariant = PriceVariant; @state.orderBook.deals deals!: OrderBookDealData[]; @@ -60,6 +61,13 @@ export default class MarketTradesWidget extends Mixins(TranslationMixin) { @getter.orderBook.baseAsset baseAsset!: AccountAsset; @getter.orderBook.quoteAsset quoteAsset!: AccountAsset; + getFontColor(side: PriceVariant): string { + const theme = this.getColorPalette(); + const color = this.isInversed(side === PriceVariant.Buy) ? theme.side.buy : theme.side.sell; + + return `color: ${color}`; + } + get completedOrders() { return this.deals.map((deal) => { const date = dayjs(deal.timestamp); @@ -83,12 +91,6 @@ export default class MarketTradesWidget extends Mixins(TranslationMixin) { font-size: var(--s-font-size-extra-small); color: var(--s-color-base-content-secondary); } - &.price { - color: var(--s-color-status-error); - &.buy { - color: var(--s-color-status-success); - } - } } &__header { diff --git a/src/components/pages/OrderBook/Popovers/PairListPopover.vue b/src/components/pages/OrderBook/Popovers/PairListPopover.vue index 7ad2f24aa..a33613a01 100644 --- a/src/components/pages/OrderBook/Popovers/PairListPopover.vue +++ b/src/components/pages/OrderBook/Popovers/PairListPopover.vue @@ -279,13 +279,13 @@ export default class PairListPopover extends Mixins( } .status-live { - color: var(--status-day-success, #34ad87); + color: var(--s-color-status-success); text-transform: uppercase; font-weight: 600; } .status-stop { - color: var(--status-day-error, #f754a3); + color: var(--s-color-status-error); text-transform: uppercase; font-weight: 600; } diff --git a/src/components/pages/OrderBook/Popovers/Settings.vue b/src/components/pages/OrderBook/Popovers/Settings.vue new file mode 100644 index 000000000..8d8f5017b --- /dev/null +++ b/src/components/pages/OrderBook/Popovers/Settings.vue @@ -0,0 +1,108 @@ + + + + + diff --git a/src/components/pages/OrderBook/Tables/OrderTable.vue b/src/components/pages/OrderBook/Tables/OrderTable.vue index 813f6b685..84e9cb1b8 100644 --- a/src/components/pages/OrderBook/Tables/OrderTable.vue +++ b/src/components/pages/OrderBook/Tables/OrderTable.vue @@ -39,7 +39,7 @@ {{ t('orderBook.orderTable.side') }} @@ -120,6 +120,7 @@ import debounce from 'lodash/debounce'; import { Component, Mixins, Prop, Watch } from 'vue-property-decorator'; import ScrollableTableMixin from '@/components/mixins/ScrollableTableMixin'; +import ThemePaletteMixin from '@/components/mixins/ThemePaletteMixin'; import TranslationMixin from '@/components/mixins/TranslationMixin'; import { getter, state } from '@/store/decorators'; import { OrderStatus } from '@/types/orderBook'; @@ -136,7 +137,7 @@ type OrderDataUI = Omit[ HistoryPagination: components.HistoryPagination, }, }) -export default class OrderTable extends Mixins(TranslationMixin, ScrollableTableMixin) { +export default class OrderTable extends Mixins(TranslationMixin, ThemePaletteMixin, ScrollableTableMixin) { readonly PriceVariant = PriceVariant; @state.settings.percentFormat private percentFormat!: Nullable; @@ -203,6 +204,13 @@ export default class OrderTable extends Mixins(TranslationMixin, ScrollableTable }); } + getFontColor(side: PriceVariant): string { + const theme = this.getColorPalette(); + const color = this.isInversed(side === PriceVariant.Buy) ? theme.side.buy : theme.side.sell; + + return `color: ${color}`; + } + getStatusTranslation(status: OrderStatusType | undefined): string { switch (status) { case OrderStatus.Active: diff --git a/src/components/pages/Stats/SupplyChart.vue b/src/components/pages/Stats/SupplyChart.vue index 3bcea4290..4df39b6d3 100644 --- a/src/components/pages/Stats/SupplyChart.vue +++ b/src/components/pages/Stats/SupplyChart.vue @@ -182,7 +182,7 @@ export default class StatsSupplyChart extends Mixins(mixins.LoadingMixin, ChartS this.lineSeriesSpec({ encode: { y: 'value' }, itemStyle: { - color: this.theme.color.status.info, + color: this.chartTheme.color.status.info, }, name: 'Supply', yAxisIndex: 1, @@ -192,7 +192,7 @@ export default class StatsSupplyChart extends Mixins(mixins.LoadingMixin, ChartS type: 'bar', encode: { y: 'mint' }, itemStyle: { - color: this.theme.color.status.success, + color: this.chartTheme.color.status.success, opacity: 0.5, }, name: 'Remint', @@ -203,7 +203,7 @@ export default class StatsSupplyChart extends Mixins(mixins.LoadingMixin, ChartS type: 'bar', encode: { y: 'burn' }, itemStyle: { - color: this.theme.color.status.error, + color: this.chartTheme.color.status.error, opacity: 0.5, }, name: 'Burn', @@ -217,7 +217,7 @@ export default class StatsSupplyChart extends Mixins(mixins.LoadingMixin, ChartS left: 'center', icon: 'circle', textStyle: { - color: this.theme.color.base.content.primary, + color: this.chartTheme.color.base.content.primary, fontSize: 12, fontWeight: 400, lineHeight: 1.5, diff --git a/src/components/shared/PriceChange.vue b/src/components/shared/PriceChange.vue index 9b1dbf15b..504421871 100644 --- a/src/components/shared/PriceChange.vue +++ b/src/components/shared/PriceChange.vue @@ -1,5 +1,5 @@