Feature/refactor appearance to color scheme (#1364)
* Refactor appearance to colorScheme * Update changelog
This commit is contained in:
parent
9ff8cd5471
commit
eac52a215b
@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Persisted the language on url change
|
||||
- Improved the portfolio evolution chart
|
||||
- Removed the data source type `RAKUTEN`
|
||||
- Refactored the appearance (dark mode) in user settings (from `appearance` to `colorScheme`)
|
||||
|
||||
## 1.204.1 - 15.10.2022
|
||||
|
||||
|
@ -1,4 +1,8 @@
|
||||
import type { Appearance, DateRange, ViewMode } from '@ghostfolio/common/types';
|
||||
import type {
|
||||
ColorScheme,
|
||||
DateRange,
|
||||
ViewMode
|
||||
} from '@ghostfolio/common/types';
|
||||
import {
|
||||
IsBoolean,
|
||||
IsIn,
|
||||
@ -8,10 +12,6 @@ import {
|
||||
} from 'class-validator';
|
||||
|
||||
export class UpdateUserSettingDto {
|
||||
@IsIn(<Appearance[]>['DARK', 'LIGHT'])
|
||||
@IsOptional()
|
||||
appearance?: Appearance;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
baseCurrency?: string;
|
||||
@ -20,6 +20,10 @@ export class UpdateUserSettingDto {
|
||||
@IsOptional()
|
||||
benchmark?: string;
|
||||
|
||||
@IsIn(<ColorScheme[]>['DARK', 'LIGHT'])
|
||||
@IsOptional()
|
||||
colorScheme?: ColorScheme;
|
||||
|
||||
@IsIn(<DateRange[]>['1d', '1y', '5y', 'max', 'ytd'])
|
||||
@IsOptional()
|
||||
dateRange?: DateRange;
|
||||
|
@ -13,7 +13,7 @@ import {
|
||||
} from '@ghostfolio/common/config';
|
||||
import { InfoItem, User } from '@ghostfolio/common/interfaces';
|
||||
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
|
||||
import { Appearance } from '@ghostfolio/common/types';
|
||||
import { ColorScheme } from '@ghostfolio/common/types';
|
||||
import { MaterialCssVarsService } from 'angular-material-css-vars';
|
||||
import { DeviceDetectorService } from 'ngx-device-detector';
|
||||
import { Subject } from 'rxjs';
|
||||
@ -78,7 +78,7 @@ export class AppComponent implements OnDestroy, OnInit {
|
||||
permissions.createUserAccount
|
||||
);
|
||||
|
||||
this.initializeTheme(this.user?.settings.appearance);
|
||||
this.initializeTheme(this.user?.settings.colorScheme);
|
||||
|
||||
this.changeDetectorRef.markForCheck();
|
||||
});
|
||||
@ -100,15 +100,15 @@ export class AppComponent implements OnDestroy, OnInit {
|
||||
this.unsubscribeSubject.complete();
|
||||
}
|
||||
|
||||
private initializeTheme(userPreferredAppearance?: Appearance) {
|
||||
const isDarkTheme = userPreferredAppearance
|
||||
? userPreferredAppearance === 'DARK'
|
||||
private initializeTheme(userPreferredColorScheme?: ColorScheme) {
|
||||
const isDarkTheme = userPreferredColorScheme
|
||||
? userPreferredColorScheme === 'DARK'
|
||||
: window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
|
||||
this.materialCssVarsService.setDarkTheme(isDarkTheme);
|
||||
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addListener((event) => {
|
||||
if (!this.user?.settings.appearance) {
|
||||
if (!this.user?.settings.colorScheme) {
|
||||
this.materialCssVarsService.setDarkTheme(event.matches);
|
||||
}
|
||||
});
|
||||
|
@ -23,6 +23,8 @@ import {
|
||||
parseDate
|
||||
} from '@ghostfolio/common/helper';
|
||||
import { LineChartItem, User } from '@ghostfolio/common/interfaces';
|
||||
import { ColorScheme } from '@ghostfolio/common/types';
|
||||
import { SymbolProfile } from '@prisma/client';
|
||||
import {
|
||||
Chart,
|
||||
LineController,
|
||||
@ -33,7 +35,6 @@ import {
|
||||
Tooltip
|
||||
} from 'chart.js';
|
||||
import annotationPlugin from 'chartjs-plugin-annotation';
|
||||
import { SymbolProfile } from '@prisma/client';
|
||||
|
||||
@Component({
|
||||
selector: 'gf-benchmark-comparator',
|
||||
@ -45,6 +46,7 @@ export class BenchmarkComparatorComponent implements OnChanges, OnDestroy {
|
||||
@Input() benchmarkDataItems: LineChartItem[] = [];
|
||||
@Input() benchmark: string;
|
||||
@Input() benchmarks: Partial<SymbolProfile>[];
|
||||
@Input() colorScheme: ColorScheme;
|
||||
@Input() daysInMarket: number;
|
||||
@Input() isLoading: boolean;
|
||||
@Input() locale: string;
|
||||
@ -127,7 +129,7 @@ export class BenchmarkComparatorComponent implements OnChanges, OnDestroy {
|
||||
tension: 0
|
||||
},
|
||||
point: {
|
||||
hoverBackgroundColor: getBackgroundColor(),
|
||||
hoverBackgroundColor: getBackgroundColor(this.colorScheme),
|
||||
hoverRadius: 2,
|
||||
radius: 0
|
||||
}
|
||||
@ -138,7 +140,7 @@ export class BenchmarkComparatorComponent implements OnChanges, OnDestroy {
|
||||
annotation: {
|
||||
annotations: {
|
||||
yAxis: {
|
||||
borderColor: `rgba(${getTextColor()}, 0.1)`,
|
||||
borderColor: `rgba(${getTextColor(this.colorScheme)}, 0.1)`,
|
||||
borderWidth: 1,
|
||||
scaleID: 'y',
|
||||
type: 'line',
|
||||
@ -151,7 +153,7 @@ export class BenchmarkComparatorComponent implements OnChanges, OnDestroy {
|
||||
},
|
||||
tooltip: this.getTooltipPluginConfiguration(),
|
||||
verticalHoverLine: {
|
||||
color: `rgba(${getTextColor()}, 0.1)`
|
||||
color: `rgba(${getTextColor(this.colorScheme)}, 0.1)`
|
||||
}
|
||||
},
|
||||
responsive: true,
|
||||
@ -159,9 +161,9 @@ export class BenchmarkComparatorComponent implements OnChanges, OnDestroy {
|
||||
x: {
|
||||
display: true,
|
||||
grid: {
|
||||
borderColor: `rgba(${getTextColor()}, 0.1)`,
|
||||
borderColor: `rgba(${getTextColor(this.colorScheme)}, 0.1)`,
|
||||
borderWidth: 1,
|
||||
color: `rgba(${getTextColor()}, 0.8)`,
|
||||
color: `rgba(${getTextColor(this.colorScheme)}, 0.8)`,
|
||||
display: false
|
||||
},
|
||||
type: 'time',
|
||||
@ -173,8 +175,8 @@ export class BenchmarkComparatorComponent implements OnChanges, OnDestroy {
|
||||
y: {
|
||||
display: true,
|
||||
grid: {
|
||||
borderColor: `rgba(${getTextColor()}, 0.1)`,
|
||||
color: `rgba(${getTextColor()}, 0.8)`,
|
||||
borderColor: `rgba(${getTextColor(this.colorScheme)}, 0.1)`,
|
||||
color: `rgba(${getTextColor(this.colorScheme)}, 0.8)`,
|
||||
display: false,
|
||||
drawBorder: false
|
||||
},
|
||||
@ -190,7 +192,9 @@ export class BenchmarkComparatorComponent implements OnChanges, OnDestroy {
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: [getVerticalHoverLinePlugin(this.chartCanvas)],
|
||||
plugins: [
|
||||
getVerticalHoverLinePlugin(this.chartCanvas, this.colorScheme)
|
||||
],
|
||||
type: 'line'
|
||||
});
|
||||
}
|
||||
@ -200,6 +204,7 @@ export class BenchmarkComparatorComponent implements OnChanges, OnDestroy {
|
||||
private getTooltipPluginConfiguration() {
|
||||
return {
|
||||
...getTooltipOptions({
|
||||
colorScheme: this.colorScheme,
|
||||
locale: this.locale,
|
||||
unit: '%'
|
||||
}),
|
||||
|
@ -127,6 +127,7 @@ export class HomeHoldingsComponent implements OnDestroy, OnInit {
|
||||
dataSource,
|
||||
symbol,
|
||||
baseCurrency: this.user?.settings?.baseCurrency,
|
||||
colorScheme: this.user?.settings?.colorScheme,
|
||||
deviceType: this.deviceType,
|
||||
hasImpersonationId: this.hasImpersonationId,
|
||||
hasPermissionToReportDataGlitch: hasPermission(
|
||||
|
@ -16,8 +16,9 @@
|
||||
class="position-absolute"
|
||||
symbol="Performance"
|
||||
unit="%"
|
||||
[historicalDataItems]="historicalDataItems"
|
||||
[colorScheme]="user?.settings?.colorScheme"
|
||||
[hidden]="historicalDataItems?.length === 0"
|
||||
[historicalDataItems]="historicalDataItems"
|
||||
[isAnimated]="user?.settings?.dateRange === '1d' ? false : true"
|
||||
[locale]="user?.settings?.locale"
|
||||
[ngClass]="{ 'pr-3': deviceType === 'mobile' }"
|
||||
|
@ -24,7 +24,7 @@ import {
|
||||
} from '@ghostfolio/common/helper';
|
||||
import { LineChartItem } from '@ghostfolio/common/interfaces';
|
||||
import { InvestmentItem } from '@ghostfolio/common/interfaces/investment-item.interface';
|
||||
import { DateRange, GroupBy } from '@ghostfolio/common/types';
|
||||
import { ColorScheme, DateRange, GroupBy } from '@ghostfolio/common/types';
|
||||
import {
|
||||
BarController,
|
||||
BarElement,
|
||||
@ -47,6 +47,7 @@ import { addDays, format, isAfter, parseISO, subDays } from 'date-fns';
|
||||
})
|
||||
export class InvestmentChartComponent implements OnChanges, OnDestroy {
|
||||
@Input() benchmarkDataItems: InvestmentItem[] = [];
|
||||
@Input() colorScheme: ColorScheme;
|
||||
@Input() currency: string;
|
||||
@Input() daysInMarket: number;
|
||||
@Input() groupBy: GroupBy;
|
||||
@ -180,7 +181,7 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy {
|
||||
tension: 0
|
||||
},
|
||||
point: {
|
||||
hoverBackgroundColor: getBackgroundColor(),
|
||||
hoverBackgroundColor: getBackgroundColor(this.colorScheme),
|
||||
hoverRadius: 2,
|
||||
radius: 0
|
||||
}
|
||||
@ -213,7 +214,7 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy {
|
||||
}
|
||||
: undefined,
|
||||
yAxis: {
|
||||
borderColor: `rgba(${getTextColor()}, 0.1)`,
|
||||
borderColor: `rgba(${getTextColor(this.colorScheme)}, 0.1)`,
|
||||
borderWidth: 1,
|
||||
scaleID: 'y',
|
||||
type: 'line',
|
||||
@ -226,7 +227,7 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy {
|
||||
},
|
||||
tooltip: this.getTooltipPluginConfiguration(),
|
||||
verticalHoverLine: {
|
||||
color: `rgba(${getTextColor()}, 0.1)`
|
||||
color: `rgba(${getTextColor(this.colorScheme)}, 0.1)`
|
||||
}
|
||||
},
|
||||
responsive: true,
|
||||
@ -234,9 +235,9 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy {
|
||||
x: {
|
||||
display: true,
|
||||
grid: {
|
||||
borderColor: `rgba(${getTextColor()}, 0.1)`,
|
||||
borderColor: `rgba(${getTextColor(this.colorScheme)}, 0.1)`,
|
||||
borderWidth: this.groupBy ? 0 : 1,
|
||||
color: `rgba(${getTextColor()}, 0.8)`,
|
||||
color: `rgba(${getTextColor(this.colorScheme)}, 0.8)`,
|
||||
display: false
|
||||
},
|
||||
type: 'time',
|
||||
@ -248,8 +249,8 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy {
|
||||
y: {
|
||||
display: !this.isInPercent,
|
||||
grid: {
|
||||
borderColor: `rgba(${getTextColor()}, 0.1)`,
|
||||
color: `rgba(${getTextColor()}, 0.8)`,
|
||||
borderColor: `rgba(${getTextColor(this.colorScheme)}, 0.1)`,
|
||||
color: `rgba(${getTextColor(this.colorScheme)}, 0.8)`,
|
||||
display: false,
|
||||
drawBorder: false
|
||||
},
|
||||
@ -265,7 +266,9 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy {
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: [getVerticalHoverLinePlugin(this.chartCanvas)],
|
||||
plugins: [
|
||||
getVerticalHoverLinePlugin(this.chartCanvas, this.colorScheme)
|
||||
],
|
||||
type: this.groupBy ? 'bar' : 'line'
|
||||
});
|
||||
}
|
||||
@ -277,6 +280,7 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy {
|
||||
private getTooltipPluginConfiguration() {
|
||||
return {
|
||||
...getTooltipOptions({
|
||||
colorScheme: this.colorScheme,
|
||||
currency: this.isInPercent ? undefined : this.currency,
|
||||
locale: this.isInPercent ? undefined : this.locale,
|
||||
unit: this.isInPercent ? '%' : undefined
|
||||
|
@ -1,7 +1,9 @@
|
||||
import { ColorScheme } from '@ghostfolio/common/types';
|
||||
import { DataSource } from '@prisma/client';
|
||||
|
||||
export interface PositionDetailDialogParams {
|
||||
baseCurrency: string;
|
||||
colorScheme: ColorScheme;
|
||||
dataSource: DataSource;
|
||||
deviceType: string;
|
||||
hasImpersonationId: boolean;
|
||||
|
@ -20,9 +20,10 @@
|
||||
</div>
|
||||
|
||||
<gf-line-chart
|
||||
class="mb-4"
|
||||
benchmarkLabel="Average Unit Price"
|
||||
class="mb-4"
|
||||
[benchmarkDataItems]="benchmarkDataItems"
|
||||
[colorScheme]="data.colorScheme"
|
||||
[currency]="SymbolProfile?.currency"
|
||||
[historicalDataItems]="historicalDataItems"
|
||||
[isAnimated]="true"
|
||||
@ -188,6 +189,7 @@
|
||||
<div class="h5" i18n>Sectors</div>
|
||||
<gf-portfolio-proportion-chart
|
||||
[baseCurrency]="user?.settings?.baseCurrency"
|
||||
[colorScheme]="data.colorScheme"
|
||||
[isInPercent]="true"
|
||||
[keys]="['name']"
|
||||
[locale]="user?.settings?.locale"
|
||||
@ -199,6 +201,7 @@
|
||||
<div class="h5" i18n>Countries</div>
|
||||
<gf-portfolio-proportion-chart
|
||||
[baseCurrency]="user?.settings?.baseCurrency"
|
||||
[colorScheme]="data.colorScheme"
|
||||
[isInPercent]="true"
|
||||
[keys]="['name']"
|
||||
[locale]="user?.settings?.locale"
|
||||
|
@ -200,12 +200,12 @@
|
||||
class="compact-with-outline w-100 without-hint"
|
||||
>
|
||||
<mat-select
|
||||
name="appearance"
|
||||
class="with-placeholder-as-option"
|
||||
name="colorScheme"
|
||||
[disabled]="!hasPermissionToUpdateUserSettings"
|
||||
[placeholder]="appearancePlaceholder"
|
||||
[value]="user.settings.appearance"
|
||||
(selectionChange)="onChangeUserSetting('appearance', $event.value)"
|
||||
[value]="user?.settings?.colorScheme"
|
||||
(selectionChange)="onChangeUserSetting('colorScheme', $event.value)"
|
||||
>
|
||||
<mat-option i18n [value]="null">Auto</mat-option>
|
||||
<mat-option i18n value="LIGHT">Light</mat-option>
|
||||
@ -267,8 +267,8 @@
|
||||
class="align-items-center d-flex justify-content-center"
|
||||
color="primary"
|
||||
mat-fab
|
||||
[routerLink]="[]"
|
||||
[queryParams]="{ createDialog: true }"
|
||||
[routerLink]="[]"
|
||||
>
|
||||
<ion-icon name="add-outline" size="large"></ion-icon>
|
||||
</a>
|
||||
|
@ -450,6 +450,7 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
|
||||
dataSource,
|
||||
symbol,
|
||||
baseCurrency: this.user?.settings?.baseCurrency,
|
||||
colorScheme: this.user?.settings?.colorScheme,
|
||||
deviceType: this.deviceType,
|
||||
hasImpersonationId: this.hasImpersonationId,
|
||||
hasPermissionToReportDataGlitch: hasPermission(
|
||||
|
@ -50,6 +50,7 @@
|
||||
<gf-portfolio-proportion-chart
|
||||
cursor="pointer"
|
||||
[baseCurrency]="user?.settings?.baseCurrency"
|
||||
[colorScheme]="user?.settings?.colorScheme"
|
||||
[isInPercent]="hasImpersonationId || user.settings.isRestrictedView"
|
||||
[keys]="['id']"
|
||||
[locale]="user?.settings?.locale"
|
||||
@ -79,6 +80,7 @@
|
||||
<mat-card-content>
|
||||
<gf-portfolio-proportion-chart
|
||||
[baseCurrency]="user?.settings?.baseCurrency"
|
||||
[colorScheme]="user?.settings?.colorScheme"
|
||||
[isInPercent]="hasImpersonationId || user.settings.isRestrictedView"
|
||||
[keys]="['currency']"
|
||||
[locale]="user?.settings?.locale"
|
||||
@ -107,6 +109,7 @@
|
||||
<mat-card-content>
|
||||
<gf-portfolio-proportion-chart
|
||||
[baseCurrency]="user?.settings?.baseCurrency"
|
||||
[colorScheme]="user?.settings?.colorScheme"
|
||||
[isInPercent]="hasImpersonationId || user.settings.isRestrictedView"
|
||||
[keys]="['assetClass', 'assetSubClass']"
|
||||
[locale]="user?.settings?.locale"
|
||||
@ -133,6 +136,7 @@
|
||||
class="mx-auto"
|
||||
cursor="pointer"
|
||||
[baseCurrency]="user?.settings?.baseCurrency"
|
||||
[colorScheme]="user?.settings?.colorScheme"
|
||||
[isInPercent]="hasImpersonationId || user.settings.isRestrictedView"
|
||||
[keys]="['symbol']"
|
||||
[locale]="user?.settings?.locale"
|
||||
@ -163,6 +167,7 @@
|
||||
<mat-card-content>
|
||||
<gf-portfolio-proportion-chart
|
||||
[baseCurrency]="user?.settings?.baseCurrency"
|
||||
[colorScheme]="user?.settings?.colorScheme"
|
||||
[isInPercent]="hasImpersonationId || user.settings.isRestrictedView"
|
||||
[keys]="['name']"
|
||||
[locale]="user?.settings?.locale"
|
||||
@ -192,6 +197,7 @@
|
||||
<mat-card-content>
|
||||
<gf-portfolio-proportion-chart
|
||||
[baseCurrency]="user?.settings?.baseCurrency"
|
||||
[colorScheme]="user?.settings?.colorScheme"
|
||||
[isInPercent]="hasImpersonationId || user.settings.isRestrictedView"
|
||||
[keys]="['name']"
|
||||
[locale]="user?.settings?.locale"
|
||||
@ -220,6 +226,7 @@
|
||||
<mat-card-content>
|
||||
<gf-portfolio-proportion-chart
|
||||
[baseCurrency]="user?.settings?.baseCurrency"
|
||||
[colorScheme]="user?.settings?.colorScheme"
|
||||
[isInPercent]="hasImpersonationId || user.settings.isRestrictedView"
|
||||
[keys]="['name']"
|
||||
[locale]="user?.settings?.locale"
|
||||
|
@ -15,6 +15,7 @@
|
||||
[benchmark]="user?.settings?.benchmark"
|
||||
[benchmarkDataItems]="benchmarkDataItems"
|
||||
[benchmarks]="benchmarks"
|
||||
[colorScheme]="user?.settings?.colorScheme"
|
||||
[daysInMarket]="daysInMarket"
|
||||
[isLoading]="isLoadingBenchmarkComparator"
|
||||
[locale]="user?.settings?.locale"
|
||||
|
@ -5,6 +5,7 @@
|
||||
<div>
|
||||
<h4 class="mb-3" i18n>Calculator</h4>
|
||||
<gf-fire-calculator
|
||||
[colorScheme]="user?.settings?.colorScheme"
|
||||
[currency]="user?.settings?.baseCurrency"
|
||||
[deviceType]="deviceType"
|
||||
[fireWealth]="fireWealth?.toNumber()"
|
||||
|
@ -192,6 +192,7 @@ export class HoldingsPageComponent implements OnDestroy, OnInit {
|
||||
dataSource,
|
||||
symbol,
|
||||
baseCurrency: this.user?.settings?.baseCurrency,
|
||||
colorScheme: this.user?.settings?.colorScheme,
|
||||
deviceType: this.deviceType,
|
||||
hasImpersonationId: this.hasImpersonationId,
|
||||
hasPermissionToReportDataGlitch: hasPermission(
|
||||
|
@ -405,6 +405,7 @@ export class TransactionsPageComponent implements OnDestroy, OnInit {
|
||||
dataSource,
|
||||
symbol,
|
||||
baseCurrency: this.user?.settings?.baseCurrency,
|
||||
colorScheme: this.user?.settings?.colorScheme,
|
||||
deviceType: this.deviceType,
|
||||
hasImpersonationId: this.hasImpersonationId,
|
||||
hasPermissionToReportDataGlitch: hasPermission(
|
||||
|
@ -1,21 +1,24 @@
|
||||
import { Chart, TooltipPosition } from 'chart.js';
|
||||
|
||||
import { getBackgroundColor, getTextColor } from './helper';
|
||||
import { ColorScheme } from './types';
|
||||
|
||||
export function getTooltipOptions({
|
||||
colorScheme,
|
||||
currency = '',
|
||||
locale = '',
|
||||
unit = ''
|
||||
}: {
|
||||
colorScheme?: ColorScheme;
|
||||
currency?: string;
|
||||
locale?: string;
|
||||
unit?: string;
|
||||
} = {}) {
|
||||
return {
|
||||
backgroundColor: getBackgroundColor(),
|
||||
bodyColor: `rgb(${getTextColor()})`,
|
||||
backgroundColor: getBackgroundColor(colorScheme),
|
||||
bodyColor: `rgb(${getTextColor(colorScheme)})`,
|
||||
borderWidth: 1,
|
||||
borderColor: `rgba(${getTextColor()}, 0.1)`,
|
||||
borderColor: `rgba(${getTextColor(colorScheme)}, 0.1)`,
|
||||
callbacks: {
|
||||
label: (context) => {
|
||||
let label = context.dataset.label || '';
|
||||
@ -39,12 +42,12 @@ export function getTooltipOptions({
|
||||
},
|
||||
caretSize: 0,
|
||||
cornerRadius: 2,
|
||||
footerColor: `rgb(${getTextColor()})`,
|
||||
footerColor: `rgb(${getTextColor(colorScheme)})`,
|
||||
itemSort: (a, b) => {
|
||||
// Reverse order
|
||||
return b.datasetIndex - a.datasetIndex;
|
||||
},
|
||||
titleColor: `rgb(${getTextColor()})`,
|
||||
titleColor: `rgb(${getTextColor(colorScheme)})`,
|
||||
usePointStyle: true
|
||||
};
|
||||
}
|
||||
@ -62,7 +65,10 @@ export function getTooltipPositionerMapTop(
|
||||
};
|
||||
}
|
||||
|
||||
export function getVerticalHoverLinePlugin(chartCanvas) {
|
||||
export function getVerticalHoverLinePlugin(
|
||||
chartCanvas,
|
||||
colorScheme?: ColorScheme
|
||||
) {
|
||||
return {
|
||||
afterDatasetsDraw: (chart, x, options) => {
|
||||
const active = chart.getActiveElements();
|
||||
@ -71,7 +77,7 @@ export function getVerticalHoverLinePlugin(chartCanvas) {
|
||||
return;
|
||||
}
|
||||
|
||||
const color = options.color || `rgb(${getTextColor()})`;
|
||||
const color = options.color || `rgb(${getTextColor(colorScheme)})`;
|
||||
const width = options.width || 1;
|
||||
|
||||
const {
|
||||
|
@ -5,6 +5,7 @@ import { de, es, it, nl } from 'date-fns/locale';
|
||||
|
||||
import { ghostfolioScraperApiSymbolPrefix, locale } from './config';
|
||||
import { Benchmark } from './interfaces';
|
||||
import { ColorScheme } from './types';
|
||||
|
||||
const NUMERIC_REGEXP = /[-]{0,1}[\d]*[.,]{0,1}[\d]+/g;
|
||||
|
||||
@ -58,8 +59,9 @@ export function extractNumberFromString(aString: string): number {
|
||||
}
|
||||
}
|
||||
|
||||
export function getBackgroundColor() {
|
||||
export function getBackgroundColor(aColorScheme: ColorScheme) {
|
||||
return getCssVariable(
|
||||
aColorScheme === 'DARK' ||
|
||||
window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||
? '--dark-background'
|
||||
: '--light-background'
|
||||
@ -133,8 +135,9 @@ export function getNumberFormatGroup(aLocale?: string) {
|
||||
}).value;
|
||||
}
|
||||
|
||||
export function getTextColor() {
|
||||
export function getTextColor(aColorScheme: ColorScheme) {
|
||||
const cssVariable = getCssVariable(
|
||||
aColorScheme === 'DARK' ||
|
||||
window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||
? '--light-primary-text'
|
||||
: '--dark-primary-text'
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { DateRange, ViewMode, Appearance } from '@ghostfolio/common/types';
|
||||
import { ColorScheme, DateRange, ViewMode } from '@ghostfolio/common/types';
|
||||
|
||||
export interface UserSettings {
|
||||
appearance?: Appearance;
|
||||
baseCurrency?: string;
|
||||
benchmark?: string;
|
||||
colorScheme?: ColorScheme;
|
||||
dateRange?: DateRange;
|
||||
emergencyFund?: number;
|
||||
isExperimentalFeatures?: boolean;
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { SubscriptionType } from '@ghostfolio/common/types/subscription.type';
|
||||
import { Account, Settings, User } from '@prisma/client';
|
||||
|
||||
import { UserSettings } from './user-settings.interface';
|
||||
|
||||
export type UserWithSettings = User & {
|
||||
|
@ -1 +0,0 @@
|
||||
export type Appearance = 'DARK' | 'LIGHT';
|
1
libs/common/src/lib/types/color-scheme.ts
Normal file
1
libs/common/src/lib/types/color-scheme.ts
Normal file
@ -0,0 +1 @@
|
||||
export type ColorScheme = 'DARK' | 'LIGHT';
|
@ -1,5 +1,6 @@
|
||||
import type { AccessWithGranteeUser } from './access-with-grantee-user.type';
|
||||
import { AccountWithValue } from './account-with-value.type';
|
||||
import type { ColorScheme } from './color-scheme';
|
||||
import type { DateRange } from './date-range.type';
|
||||
import type { Granularity } from './granularity.type';
|
||||
import { GroupBy } from './group-by.type';
|
||||
@ -9,12 +10,11 @@ import type { OrderWithAccount } from './order-with-account.type';
|
||||
import type { RequestWithUser } from './request-with-user.type';
|
||||
import { ToggleOption } from './toggle-option.type';
|
||||
import type { ViewMode } from './view-mode.type';
|
||||
import type { Appearance } from './appearance.type';
|
||||
|
||||
export type {
|
||||
Appearance,
|
||||
AccessWithGranteeUser,
|
||||
AccountWithValue,
|
||||
ColorScheme,
|
||||
DateRange,
|
||||
Granularity,
|
||||
GroupBy,
|
||||
|
@ -1,4 +1,5 @@
|
||||
import '@angular/localize/init';
|
||||
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
|
@ -16,6 +16,7 @@ import { FormBuilder, FormControl } from '@angular/forms';
|
||||
import { getTooltipOptions } from '@ghostfolio/common/chart-helper';
|
||||
import { primaryColorRgb } from '@ghostfolio/common/config';
|
||||
import { transformTickToAbbreviation } from '@ghostfolio/common/helper';
|
||||
import { ColorScheme } from '@ghostfolio/common/types';
|
||||
import {
|
||||
BarController,
|
||||
BarElement,
|
||||
@ -40,6 +41,7 @@ import { FireCalculatorService } from './fire-calculator.service';
|
||||
export class FireCalculatorComponent
|
||||
implements AfterViewInit, OnChanges, OnDestroy
|
||||
{
|
||||
@Input() colorScheme: ColorScheme;
|
||||
@Input() currency: string;
|
||||
@Input() deviceType: string;
|
||||
@Input() fireWealth: number;
|
||||
@ -182,7 +184,7 @@ export class FireCalculatorComponent
|
||||
options: {
|
||||
plugins: {
|
||||
tooltip: {
|
||||
...getTooltipOptions(),
|
||||
...getTooltipOptions({ colorScheme: this.colorScheme }),
|
||||
mode: 'index',
|
||||
callbacks: {
|
||||
footer: (items) => {
|
||||
|
@ -26,6 +26,7 @@ import {
|
||||
getTextColor
|
||||
} from '@ghostfolio/common/helper';
|
||||
import { LineChartItem } from '@ghostfolio/common/interfaces';
|
||||
import { ColorScheme } from '@ghostfolio/common/types';
|
||||
import {
|
||||
Chart,
|
||||
Filler,
|
||||
@ -46,6 +47,7 @@ import {
|
||||
export class LineChartComponent implements AfterViewInit, OnChanges, OnDestroy {
|
||||
@Input() benchmarkDataItems: LineChartItem[] = [];
|
||||
@Input() benchmarkLabel = '';
|
||||
@Input() colorScheme: ColorScheme;
|
||||
@Input() currency: string;
|
||||
@Input() historicalDataItems: LineChartItem[];
|
||||
@Input() isAnimated = false;
|
||||
@ -140,7 +142,7 @@ export class LineChartComponent implements AfterViewInit, OnChanges, OnDestroy {
|
||||
0,
|
||||
`rgba(${primaryColorRgb.r}, ${primaryColorRgb.g}, ${primaryColorRgb.b}, 0.01)`
|
||||
);
|
||||
gradient.addColorStop(1, getBackgroundColor());
|
||||
gradient.addColorStop(1, getBackgroundColor(this.colorScheme));
|
||||
}
|
||||
|
||||
const data = {
|
||||
@ -192,7 +194,7 @@ export class LineChartComponent implements AfterViewInit, OnChanges, OnDestroy {
|
||||
aspectRatio: 16 / 9,
|
||||
elements: {
|
||||
point: {
|
||||
hoverBackgroundColor: getBackgroundColor(),
|
||||
hoverBackgroundColor: getBackgroundColor(this.colorScheme),
|
||||
hoverRadius: 2
|
||||
}
|
||||
},
|
||||
@ -205,15 +207,15 @@ export class LineChartComponent implements AfterViewInit, OnChanges, OnDestroy {
|
||||
},
|
||||
tooltip: this.getTooltipPluginConfiguration(),
|
||||
verticalHoverLine: {
|
||||
color: `rgba(${getTextColor()}, 0.1)`
|
||||
color: `rgba(${getTextColor(this.colorScheme)}, 0.1)`
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
display: this.showXAxis,
|
||||
grid: {
|
||||
borderColor: `rgba(${getTextColor()}, 0.1)`,
|
||||
color: `rgba(${getTextColor()}, 0.8)`,
|
||||
borderColor: `rgba(${getTextColor(this.colorScheme)}, 0.1)`,
|
||||
color: `rgba(${getTextColor(this.colorScheme)}, 0.8)`,
|
||||
display: false
|
||||
},
|
||||
time: {
|
||||
@ -225,8 +227,8 @@ export class LineChartComponent implements AfterViewInit, OnChanges, OnDestroy {
|
||||
y: {
|
||||
display: this.showYAxis,
|
||||
grid: {
|
||||
borderColor: `rgba(${getTextColor()}, 0.1)`,
|
||||
color: `rgba(${getTextColor()}, 0.8)`,
|
||||
borderColor: `rgba(${getTextColor(this.colorScheme)}, 0.1)`,
|
||||
color: `rgba(${getTextColor(this.colorScheme)}, 0.8)`,
|
||||
display: false
|
||||
},
|
||||
max: this.yMax,
|
||||
@ -263,7 +265,9 @@ export class LineChartComponent implements AfterViewInit, OnChanges, OnDestroy {
|
||||
},
|
||||
spanGaps: true
|
||||
},
|
||||
plugins: [getVerticalHoverLinePlugin(this.chartCanvas)],
|
||||
plugins: [
|
||||
getVerticalHoverLinePlugin(this.chartCanvas, this.colorScheme)
|
||||
],
|
||||
type: 'line'
|
||||
});
|
||||
}
|
||||
@ -300,6 +304,7 @@ export class LineChartComponent implements AfterViewInit, OnChanges, OnDestroy {
|
||||
private getTooltipPluginConfiguration() {
|
||||
return {
|
||||
...getTooltipOptions({
|
||||
colorScheme: this.colorScheme,
|
||||
currency: this.currency,
|
||||
locale: this.locale,
|
||||
unit: this.unit
|
||||
|
@ -14,6 +14,7 @@ import { getTooltipOptions } from '@ghostfolio/common/chart-helper';
|
||||
import { UNKNOWN_KEY } from '@ghostfolio/common/config';
|
||||
import { getTextColor } from '@ghostfolio/common/helper';
|
||||
import { PortfolioPosition, UniqueAsset } from '@ghostfolio/common/interfaces';
|
||||
import { ColorScheme } from '@ghostfolio/common/types';
|
||||
import { DataSource } from '@prisma/client';
|
||||
import Big from 'big.js';
|
||||
import { ChartConfiguration, Tooltip } from 'chart.js';
|
||||
@ -34,6 +35,7 @@ export class PortfolioProportionChartComponent
|
||||
implements AfterViewInit, OnChanges, OnDestroy
|
||||
{
|
||||
@Input() baseCurrency: string;
|
||||
@Input() colorScheme: ColorScheme;
|
||||
@Input() cursor: string;
|
||||
@Input() isInPercent = false;
|
||||
@Input() keys: string[] = [];
|
||||
@ -59,10 +61,7 @@ export class PortfolioProportionChartComponent
|
||||
|
||||
private colorMap: {
|
||||
[symbol: string]: string;
|
||||
} = {
|
||||
[this.OTHER_KEY]: `rgba(${getTextColor()}, 0.24)`,
|
||||
[UNKNOWN_KEY]: `rgba(${getTextColor()}, 0.12)`
|
||||
};
|
||||
} = {};
|
||||
|
||||
public constructor() {
|
||||
Chart.register(ArcElement, DoughnutController, LinearScale, Tooltip);
|
||||
@ -94,6 +93,10 @@ export class PortfolioProportionChartComponent
|
||||
value: Big;
|
||||
};
|
||||
} = {};
|
||||
this.colorMap = {
|
||||
[this.OTHER_KEY]: `rgba(${getTextColor(this.colorScheme)}, 0.24)`,
|
||||
[UNKNOWN_KEY]: `rgba(${getTextColor(this.colorScheme)}, 0.12)`
|
||||
};
|
||||
|
||||
Object.keys(this.positions).forEach((symbol) => {
|
||||
if (this.positions[symbol][this.keys[0]]) {
|
||||
@ -350,6 +353,7 @@ export class PortfolioProportionChartComponent
|
||||
private getTooltipPluginConfiguration(data: ChartConfiguration['data']) {
|
||||
return {
|
||||
...getTooltipOptions({
|
||||
colorScheme: this.colorScheme,
|
||||
currency: this.baseCurrency,
|
||||
locale: this.locale
|
||||
}),
|
||||
|
Loading…
x
Reference in New Issue
Block a user