Compare commits

..

8 Commits

Author SHA1 Message Date
805f4b05be Release 1.205.1 (#1368) 2022-10-16 20:19:27 +02:00
5b51a6840a Release 1.205.0 (#1367) 2022-10-16 19:36:51 +02:00
36bd6164e6 Feature/improve wording on landing page (#1366)
* Improve wording

* Update changelog
2022-10-16 19:35:09 +02:00
eac52a215b Feature/refactor appearance to color scheme (#1364)
* Refactor appearance to colorScheme

* Update changelog
2022-10-16 14:54:26 +02:00
9ff8cd5471 Feature/improve portfolio evolution chart (#1362)
* Switch inputs

* Update changelog
2022-10-16 10:01:31 +02:00
33cc7e4e7e Feature/remove rakuten from data source (#1361)
* Remove Rakuten

* Update changelog
2022-10-16 09:42:18 +02:00
47f84dab06 Remove postfix (#1360) 2022-10-16 09:41:41 +02:00
384d18b2a6 Feature/persist user language on url change (#1359)
* Persist user language

* Update changelog
2022-10-16 08:45:52 +02:00
40 changed files with 281 additions and 149 deletions

View File

@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## 1.205.1 - 16.10.2022
### Changed
- Persisted the language on url change
- Improved the portfolio evolution chart
- Refactored the appearance (dark mode) in user settings (from `appearance` to `colorScheme`)
- Improved the wording on the landing page
## 1.204.1 - 15.10.2022
### Added

View File

@ -238,12 +238,10 @@ export class PortfolioController {
@Headers('impersonation-id') impersonationId: string,
@Query('range') dateRange: DateRange = 'max'
): Promise<PortfolioPerformanceResponse> {
const performanceInformation = await this.portfolioService.getPerformanceV2(
{
dateRange,
impersonationId
}
);
const performanceInformation = await this.portfolioService.getPerformance({
dateRange,
impersonationId
});
if (
impersonationId ||

View File

@ -302,7 +302,7 @@ export class PortfolioService {
});
}
public async getChartV2({
public async getChart({
dateRange = 'max',
impersonationId
}: {
@ -881,7 +881,7 @@ export class PortfolioService {
};
}
public async getPerformanceV2({
public async getPerformance({
dateRange = 'max',
impersonationId
}: {
@ -945,7 +945,7 @@ export class PortfolioService {
// currentNetPerformancePercent = currentNetPerformancePercent.mul(-1);
// }
const historicalDataContainer = await this.getChartV2({
const historicalDataContainer = await this.getChart({
dateRange,
impersonationId
});
@ -1270,7 +1270,7 @@ export class PortfolioService {
const userId = await this.getUserId(impersonationId, this.request.user.id);
const user = await this.userService.user({ id: userId });
const performanceInformation = await this.getPerformanceV2({
const performanceInformation = await this.getPerformance({
impersonationId
});

View File

@ -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;

View File

@ -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);
}
});

View File

@ -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: '%'
}),

View File

@ -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(

View File

@ -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' }"

View File

@ -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,
@ -46,11 +46,12 @@ import { addDays, format, isAfter, parseISO, subDays } from 'date-fns';
styleUrls: ['./investment-chart.component.scss']
})
export class InvestmentChartComponent implements OnChanges, OnDestroy {
@Input() benchmarkDataItems: LineChartItem[] = [];
@Input() benchmarkDataItems: InvestmentItem[] = [];
@Input() colorScheme: ColorScheme;
@Input() currency: string;
@Input() daysInMarket: number;
@Input() groupBy: GroupBy;
@Input() investments: InvestmentItem[];
@Input() historicalDataItems: LineChartItem[] = [];
@Input() isInPercent = false;
@Input() locale: string;
@Input() range: DateRange = 'max';
@ -81,7 +82,7 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy {
}
public ngOnChanges() {
if (this.benchmarkDataItems && this.investments) {
if (this.benchmarkDataItems && this.historicalDataItems) {
this.initialize();
}
}
@ -94,7 +95,7 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy {
this.isLoading = true;
// Create a clone
this.data = this.investments.map((a) => Object.assign({}, a));
this.data = this.benchmarkDataItems.map((item) => Object.assign({}, item));
if (!this.groupBy && this.data?.length > 0) {
if (this.range === 'max') {
@ -122,14 +123,14 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy {
}
const data = {
labels: this.benchmarkDataItems.map(({ date }) => {
labels: this.historicalDataItems.map(({ date }) => {
return parseDate(date);
}),
datasets: [
{
backgroundColor: `rgb(${primaryColorRgb.r}, ${primaryColorRgb.g}, ${primaryColorRgb.b})`,
borderColor: `rgb(${primaryColorRgb.r}, ${primaryColorRgb.g}, ${primaryColorRgb.b})`,
borderWidth: this.groupBy ? 0 : 2,
backgroundColor: `rgb(${secondaryColorRgb.r}, ${secondaryColorRgb.g}, ${secondaryColorRgb.b})`,
borderColor: `rgb(${secondaryColorRgb.r}, ${secondaryColorRgb.g}, ${secondaryColorRgb.b})`,
borderWidth: this.groupBy ? 0 : 1,
data: this.data.map(({ date, investment }) => {
return {
x: parseDate(date),
@ -141,16 +142,16 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy {
borderColor: (context: unknown) =>
this.isInFuture(
context,
`rgba(${primaryColorRgb.r}, ${primaryColorRgb.g}, ${primaryColorRgb.b}, 0.67)`
`rgba(${secondaryColorRgb.r}, ${secondaryColorRgb.g}, ${secondaryColorRgb.b}, 0.67)`
),
borderDash: (context: unknown) => this.isInFuture(context, [2, 2])
},
stepped: true
},
{
borderColor: `rgb(${secondaryColorRgb.r}, ${secondaryColorRgb.g}, ${secondaryColorRgb.b})`,
borderWidth: 1,
data: this.benchmarkDataItems.map(({ date, value }) => {
borderColor: `rgb(${primaryColorRgb.r}, ${primaryColorRgb.g}, ${primaryColorRgb.b})`,
borderWidth: 2,
data: this.historicalDataItems.map(({ date, value }) => {
return {
x: parseDate(date),
y: this.isInPercent ? value * 100 : value
@ -180,7 +181,7 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy {
tension: 0
},
point: {
hoverBackgroundColor: getBackgroundColor(),
hoverBackgroundColor: getBackgroundColor(this.colorScheme),
hoverRadius: 2,
radius: 0
}
@ -192,13 +193,13 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy {
annotations: {
savingsRate: this.savingsRate
? {
borderColor: `rgba(${secondaryColorRgb.r}, ${secondaryColorRgb.g}, ${secondaryColorRgb.b}, 0.75)`,
borderColor: `rgba(${primaryColorRgb.r}, ${primaryColorRgb.g}, ${primaryColorRgb.b}, 0.75)`,
borderWidth: 1,
label: {
backgroundColor: `rgb(${secondaryColorRgb.r}, ${secondaryColorRgb.g}, ${secondaryColorRgb.b})`,
backgroundColor: `rgb(${primaryColorRgb.r}, ${primaryColorRgb.g}, ${primaryColorRgb.b})`,
borderRadius: 2,
color: 'white',
content: 'Savings Rate',
content: $localize`Savings Rate`,
display: true,
font: { size: '10px', weight: 'normal' },
padding: {
@ -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

View File

@ -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;

View File

@ -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"

View File

@ -5,6 +5,7 @@ import {
Router,
RouterStateSnapshot
} from '@angular/router';
import { DataService } from '@ghostfolio/client/services/data.service';
import { SettingsStorageService } from '@ghostfolio/client/services/settings-storage.service';
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { EMPTY } from 'rxjs';
@ -30,6 +31,7 @@ export class AuthGuard implements CanActivate {
];
constructor(
private dataService: DataService,
private router: Router,
private settingsStorageService: SettingsStorageService,
private userService: UserService
@ -74,7 +76,16 @@ export class AuthGuard implements CanActivate {
const userLanguage = user?.settings?.language;
if (userLanguage && document.documentElement.lang !== userLanguage) {
window.location.href = `../${userLanguage}`;
this.dataService
.putUserSetting({ language: document.documentElement.lang })
.subscribe(() => {
this.userService.remove();
setTimeout(() => {
window.location.reload();
}, 300);
});
resolve(false);
return;
} else if (

View File

@ -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>

View File

@ -3,6 +3,7 @@ import { DataService } from '@ghostfolio/client/services/data.service';
import { Statistics } from '@ghostfolio/common/interfaces/statistics.interface';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { format } from 'date-fns';
import { DeviceDetectorService } from 'ngx-device-detector';
import { Subject } from 'rxjs';
@Component({
@ -14,6 +15,7 @@ import { Subject } from 'rxjs';
export class LandingPageComponent implements OnDestroy, OnInit {
public currentYear = format(new Date(), 'yyyy');
public demoAuthToken: string;
public deviceType: string;
public hasPermissionForStatistics: boolean;
public statistics: Statistics;
public testimonials = [
@ -41,7 +43,10 @@ export class LandingPageComponent implements OnDestroy, OnInit {
private unsubscribeSubject = new Subject<void>();
public constructor(private dataService: DataService) {
public constructor(
private dataService: DataService,
private deviceService: DeviceDetectorService
) {
const { globalPermissions, statistics } = this.dataService.fetchInfo();
this.hasPermissionForStatistics = hasPermission(
@ -52,7 +57,9 @@ export class LandingPageComponent implements OnDestroy, OnInit {
this.statistics = statistics;
}
public ngOnInit() {}
public ngOnInit() {
this.deviceType = this.deviceService.getDeviceInfo().deviceType;
}
public ngOnDestroy() {
this.unsubscribeSubject.next();

View File

@ -1,10 +1,15 @@
<div class="container">
<div class="row">
<div class="col text-center">
<h1 class="font-weight-bold intro my-5">
<h1 class="font-weight-bold intro mt-5">
Manage your wealth like a boss
</h1>
<div>
<p class="lead mb-4">
Ghostfolio is a privacy-first, open source dashboard to manage your
personal finances. Break down your asset allocation, know your net worth
and make solid, data-driven investment decisions.
</p>
<div class="mb-4">
<a
href="https://www.youtube.com/watch?v=yY6ObSQVJZk"
target="_blank"
@ -23,9 +28,9 @@
</div>
<div class="container">
<div class="button-container row">
<div class="button-container mb-5 row">
<div class="align-items-center col d-flex justify-content-center">
<div class="py-5 text-center">
<div class="text-center">
<a
class="d-inline-block"
color="primary"
@ -43,7 +48,10 @@
</div>
<div *ngIf="hasPermissionForStatistics" class="row mb-5">
<div class="col-md-4 d-flex my-1">
<div
class="col-md-4 d-flex my-1"
[ngClass]="{ 'justify-content-center': this.deviceType !== 'mobile' }"
>
<a
class="d-block"
title="Ghostfolio in Numbers: Monthly Active Users (MAU)"
@ -57,7 +65,10 @@
>
</a>
</div>
<div class="col-md-4 d-flex my-1">
<div
class="col-md-4 d-flex my-1"
[ngClass]="{ 'justify-content-center': this.deviceType !== 'mobile' }"
>
<a
class="d-block"
title="Ghostfolio in Numbers: Stars on GitHub"
@ -71,7 +82,10 @@
>
</a>
</div>
<div class="col-md-4 d-flex my-1">
<div
class="col-md-4 d-flex my-1"
[ngClass]="{ 'justify-content-center': this.deviceType !== 'mobile' }"
>
<a
class="d-block"
title="Ghostfolio in Numbers: Pulls on Docker Hub"
@ -139,15 +153,15 @@
</div>
</div>
<div class="row my-5">
<div class="pt-3 row">
<div class="col text-center">
<h2 class="h4 mb-1 text-center">
Protect your <strong>assets</strong>. Refine your
<strong>personal investment strategy</strong>.
</h2>
<p class="lead">
<p class="lead m-0">
Ghostfolio empowers busy people to keep track of stocks, ETFs or
cryptocurrencies and make solid, data-driven investment decisions.
cryptocurrencies without being tracked.
</p>
</div>
</div>
@ -220,7 +234,7 @@
</li>
</ul>
<div class="mt-4 text-center">
<a [routerLink]="['/about']" mat-stroked-button
<a mat-stroked-button [routerLink]="['/about']"
>Learn more about Ghostfolio</a
>
</div>

View File

@ -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(

View File

@ -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"

View File

@ -15,6 +15,7 @@
[benchmark]="user?.settings?.benchmark"
[benchmarkDataItems]="benchmarkDataItems"
[benchmarks]="benchmarks"
[colorScheme]="user?.settings?.colorScheme"
[daysInMarket]="daysInMarket"
[isLoading]="isLoadingBenchmarkComparator"
[locale]="user?.settings?.locale"
@ -119,10 +120,10 @@
<div class="chart-container">
<gf-investment-chart
class="h-100"
[benchmarkDataItems]="performanceDataItems"
[benchmarkDataItems]="investments"
[currency]="user?.settings?.baseCurrency"
[daysInMarket]="daysInMarket"
[investments]="investments"
[historicalDataItems]="performanceDataItems"
[isInPercent]="hasImpersonationId || user.settings.isRestrictedView"
[locale]="user?.settings?.locale"
[range]="user?.settings?.dateRange"
@ -155,9 +156,9 @@
<gf-investment-chart
class="h-100"
groupBy="month"
[benchmarkDataItems]="investmentsByMonth"
[currency]="user?.settings?.baseCurrency"
[daysInMarket]="daysInMarket"
[investments]="investmentsByMonth"
[isInPercent]="hasImpersonationId || user.settings.isRestrictedView"
[locale]="user?.settings?.locale"
[range]="user?.settings?.dateRange"

View File

@ -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()"

View File

@ -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(

View File

@ -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(

View File

@ -6,74 +6,74 @@
http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
<url>
<loc>https://ghostfol.io</loc>
<lastmod>2022-10-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/de/blog/2021/07/hallo-ghostfolio</loc>
<lastmod>2022-10-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/about</loc>
<lastmod>2022-10-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/about/changelog</loc>
<lastmod>2022-10-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog</loc>
<lastmod>2022-10-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2021/07/hello-ghostfolio</loc>
<lastmod>2022-10-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2022/01/ghostfolio-first-months-in-open-source</loc>
<lastmod>2022-10-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2022/07/ghostfolio-meets-internet-identity</loc>
<lastmod>2022-10-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2022/07/how-do-i-get-my-finances-in-order</loc>
<lastmod>2022-10-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2022/08/500-stars-on-github</loc>
<lastmod>2022-10-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2022/10/hacktoberfest-2022</loc>
<lastmod>2022-10-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/demo</loc>
<lastmod>2022-10-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/faq</loc>
<lastmod>2022-10-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/features</loc>
<lastmod>2022-10-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/markets</loc>
<lastmod>2022-10-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/pricing</loc>
<lastmod>2022-10-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/register</loc>
<lastmod>2022-10-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/resources</loc>
<lastmod>2022-10-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
</urlset>

View File

@ -6,65 +6,65 @@
<meta charset="utf-8" />
<meta content="yes" name="apple-mobile-web-app-capable" />
<meta
content="Ghostfolio is a personal finance dashboard to keep track of your assets like stocks, ETFs or cryptocurrencies across multiple platforms."
name="description"
content="Ghostfolio is a lightweight application to keep track of your financial assets like stocks, ETFs or cryptocurrencies across multiple platforms."
/>
<meta
content="app, asset, cryptocurrency, dashboard, etf, finance, management, performance, portfolio, software, stock, trading, wealth, web3"
name="keywords"
content="app, asset, cryptocurrency, etf, finance, management, performance, portfolio, software, stock, tracker, trading, wealth"
/>
<meta name="mobile-web-app-capable" content="yes" />
<meta name="twitter:card" content="summary_large_image" />
<meta content="yes" name="mobile-web-app-capable" />
<meta content="summary_large_image" name="twitter:card" />
<meta
content="Ghostfolio is a personal finance dashboard to keep track of your assets like stocks, ETFs or cryptocurrencies"
name="twitter:description"
content="Ghostfolio is a lightweight wealth management application for individuals to keep track of stocks, ETFs or cryptocurrencies"
/>
<meta name="twitter:image" content="${rootUrl}/${featureGraphicPath}" />
<meta content="${rootUrl}/${featureGraphicPath}" name="twitter:image" />
<meta
content="Ghostfolio Open Source Wealth Management Software"
name="twitter:title"
content="Ghostfolio Open Source Wealth Management Software"
/>
<meta
name="viewport"
content="initial-scale=1, viewport-fit=cover, width=device-width"
name="viewport"
/>
<meta property="og:description" content="" />
<meta content="" property="og:description" />
<meta
content="Ghostfolio Open Source Wealth Management Software"
property="og:title"
content="Ghostfolio Open Source Wealth Management Software"
/>
<meta property="og:type" content="website" />
<meta property="og:url" content="${rootUrl}${path}" />
<meta property="og:image" content="${rootUrl}/${featureGraphicPath}" />
<meta property="og:updated_time" content="2022-08-18T00:00:00+00:00" />
<meta content="website" property="og:type" />
<meta content="${rootUrl}${path}" property="og:url" />
<meta content="${rootUrl}/${featureGraphicPath}" property="og:image" />
<meta content="2022-10-16T00:00:00+00:00" property="og:updated_time" />
<meta
property="og:site_name"
content="Ghostfolio Open Source Wealth Management Software"
property="og:site_name"
/>
<link
href="../assets/apple-touch-icon.png"
rel="apple-touch-icon"
sizes="180x180"
href="../assets/apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="../assets/favicon-32x32.png"
rel="icon"
sizes="32x32"
type="image/png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="../assets/favicon-16x16.png"
rel="icon"
sizes="16x16"
type="image/png"
/>
<link rel="manifest" href="../assets/site.webmanifest" />
<link href="../assets/site.webmanifest" rel="manifest" />
</head>
<body>
<gf-root></gf-root>
<script type="module" src="../ionicons/ionicons.esm.js"></script>
<script src="../ionicons/ionicons.esm.js" type="module"></script>
<script nomodule="" src="ionicons.js"></script>
<noscript

View File

@ -2729,6 +2729,14 @@
<context context-type="linenumber">112</context>
</context-group>
</trans-unit>
<trans-unit id="8192718423057883427" datatype="html">
<source>Savings Rate</source>
<target state="translated">Sparrate</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">201</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>

View File

@ -2730,6 +2730,14 @@
<context context-type="linenumber">112</context>
</context-group>
</trans-unit>
<trans-unit id="8192718423057883427" datatype="html">
<source>Savings Rate</source>
<target state="translated">Tasa de ahorro</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">201</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>

View File

@ -2730,6 +2730,14 @@
<context context-type="linenumber">112</context>
</context-group>
</trans-unit>
<trans-unit id="8192718423057883427" datatype="html">
<source>Savings Rate</source>
<target state="translated">Tasso di risparmio</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">201</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>

View File

@ -2729,6 +2729,14 @@
<context context-type="linenumber">112</context>
</context-group>
</trans-unit>
<trans-unit id="8192718423057883427" datatype="html">
<source>Savings Rate</source>
<target state="translated">Spaarquote</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">201</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>

View File

@ -2438,6 +2438,13 @@
<context context-type="linenumber">112</context>
</context-group>
</trans-unit>
<trans-unit id="8192718423057883427" datatype="html">
<source>Savings Rate</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">201</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>

View File

@ -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 {

View File

@ -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,9 +59,10 @@ export function extractNumberFromString(aString: string): number {
}
}
export function getBackgroundColor() {
export function getBackgroundColor(aColorScheme: ColorScheme) {
return getCssVariable(
window.matchMedia('(prefers-color-scheme: dark)').matches
aColorScheme === 'DARK' ||
window.matchMedia('(prefers-color-scheme: dark)').matches
? '--dark-background'
: '--light-background'
);
@ -133,9 +135,10 @@ export function getNumberFormatGroup(aLocale?: string) {
}).value;
}
export function getTextColor() {
export function getTextColor(aColorScheme: ColorScheme) {
const cssVariable = getCssVariable(
window.matchMedia('(prefers-color-scheme: dark)').matches
aColorScheme === 'DARK' ||
window.matchMedia('(prefers-color-scheme: dark)').matches
? '--light-primary-text'
: '--dark-primary-text'
);

View File

@ -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;

View File

@ -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 & {

View File

@ -1 +0,0 @@
export type Appearance = 'DARK' | 'LIGHT';

View File

@ -0,0 +1 @@
export type ColorScheme = 'DARK' | 'LIGHT';

View File

@ -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,

View File

@ -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';

View File

@ -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) => {

View File

@ -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

View File

@ -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
}),

View File

@ -1,6 +1,6 @@
{
"name": "ghostfolio",
"version": "1.204.1",
"version": "1.205.1",
"homepage": "https://ghostfol.io",
"license": "AGPL-3.0",
"scripts": {