Feature/add tabs on the home page (#230)

* Add tabs

* Update changelog
This commit is contained in:
Thomas 2021-07-26 20:23:32 +02:00 committed by GitHub
parent 6dbdf23a68
commit 40696b425e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 352 additions and 242 deletions

View File

@ -5,6 +5,12 @@ 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/), 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). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased
### Changed
- Introduced tabs on the home page
## 1.28.0 - 24.07.2021 ## 1.28.0 - 24.07.2021
### Added ### Added

View File

@ -9,7 +9,7 @@
</header> </header>
<main role="main"> <main role="main">
<div *ngIf="canCreateAccount" class="container create-account-container mb-2"> <div *ngIf="canCreateAccount" class="container create-account-container">
<div class="row"> <div class="row">
<div class="col-md-8 offset-md-2 text-center"> <div class="col-md-8 offset-md-2 text-center">
<a class="text-center" [routerLink]="['/']"> <a class="text-center" [routerLink]="['/']">

View File

@ -9,6 +9,7 @@
padding-top: 5rem; padding-top: 5rem;
.create-account-container { .create-account-container {
height: 2.5rem;
margin-top: -0.5rem; margin-top: -0.5rem;
.create-account-box { .create-account-box {

View File

@ -4,6 +4,7 @@ import {
ChangeDetectorRef, ChangeDetectorRef,
Component, Component,
ElementRef, ElementRef,
HostBinding,
OnDestroy, OnDestroy,
OnInit, OnInit,
ViewChild ViewChild
@ -38,8 +39,13 @@ import { first, takeUntil } from 'rxjs/operators';
styleUrls: ['./home-page.scss'] styleUrls: ['./home-page.scss']
}) })
export class HomePageComponent implements AfterViewInit, OnDestroy, OnInit { export class HomePageComponent implements AfterViewInit, OnDestroy, OnInit {
@HostBinding('class.with-create-account-container') get isDemo() {
return this.canCreateAccount;
}
@ViewChild('positionsContainer') positionsContainer: ElementRef; @ViewChild('positionsContainer') positionsContainer: ElementRef;
public canCreateAccount: boolean;
public dateRange: DateRange; public dateRange: DateRange;
public dateRangeOptions: ToggleOption[] = [ public dateRangeOptions: ToggleOption[] = [
{ label: 'Today', value: '1d' }, { label: 'Today', value: '1d' },
@ -95,6 +101,11 @@ export class HomePageComponent implements AfterViewInit, OnDestroy, OnInit {
if (state?.user) { if (state?.user) {
this.user = state.user; this.user = state.user;
this.canCreateAccount = hasPermission(
this.user?.permissions,
permissions.createUserAccount
);
this.hasPermissionToAccessFearAndGreedIndex = hasPermission( this.hasPermissionToAccessFearAndGreedIndex = hasPermission(
this.user.permissions, this.user.permissions,
permissions.accessFearAndGreedIndex permissions.accessFearAndGreedIndex

View File

@ -1,108 +1,144 @@
<ng-container *ngIf="hasPositions || !historicalDataItems"> <mat-tab-group
<div class="container overview position-relative"> animationDuration="0ms"
<div class="row"> class="position-absolute"
<a headerPosition="below"
class="chart-container col mr-3" mat-align-tabs="center"
[routerLink]="[]" >
[queryParams]="{performanceChartDialog: true}" <mat-tab>
> <ng-template mat-tab-label>
<gf-line-chart <ion-icon name="analytics-outline" size="large"></ion-icon>
symbol="Performance" </ng-template>
[historicalDataItems]="historicalDataItems" <div
[showLoader]="false" class="
[showXAxis]="false" align-items-center
[showYAxis]="false" container
></gf-line-chart> d-flex
</a> flex-column
</div> h-100
<div class="overview-container row mb-5 mt-1"> justify-content-center
<div class="col"> overview
<gf-portfolio-performance-summary p-3
class="pb-4" position-relative
[baseCurrency]="user?.settings?.baseCurrency" "
[isLoading]="isLoadingPerformance" >
[locale]="user?.settings?.locale" <div class="row w-100">
[performance]="performance" <a
[showDetails]="!hasImpersonationId || hasPermissionToReadForeignPortfolio" *ngIf="historicalDataItems?.length !== 0"
></gf-portfolio-performance-summary> class="chart-container col"
<div class="text-center"> [routerLink]="[]"
<gf-toggle [queryParams]="{performanceChartDialog: true}"
[defaultValue]="dateRange" >
<gf-line-chart
class="mr-3"
symbol="Performance"
[historicalDataItems]="historicalDataItems"
[showLoader]="false"
[showXAxis]="false"
[showYAxis]="false"
></gf-line-chart>
</a>
<div
*ngIf="historicalDataItems?.length === 0"
class="
align-items-center
chart-container
d-flex
justify-content-center
w-100
"
>
<div class="d-flex justify-content-center">
<gf-no-transactions-info-indicator></gf-no-transactions-info-indicator>
</div>
</div>
</div>
<div class="overview-container row mt-1">
<div class="col">
<gf-portfolio-performance-summary
class="pb-4"
[baseCurrency]="user?.settings?.baseCurrency"
[isLoading]="isLoadingPerformance" [isLoading]="isLoadingPerformance"
[options]="dateRangeOptions" [locale]="user?.settings?.locale"
(change)="onChangeDateRange($event.value)" [performance]="performance"
></gf-toggle> [showDetails]="!hasImpersonationId || hasPermissionToReadForeignPortfolio"
></gf-portfolio-performance-summary>
<div class="text-center">
<gf-toggle
[defaultValue]="dateRange"
[isLoading]="isLoadingPerformance"
[options]="dateRangeOptions"
(change)="onChangeDateRange($event.value)"
></gf-toggle>
</div>
</div> </div>
</div> </div>
</div> </div>
<div </mat-tab>
class="button-container d-flex justify-content-center position-absolute" <mat-tab>
> <ng-template mat-tab-label>
<a <ion-icon name="wallet-outline" size="large"></ion-icon>
*ngIf="showPositionsButton" </ng-template>
[routerLink]="['/home']" <div class="container justify-content-center p-3 positions">
fragment="positions-container" <div class="row">
i18n <div class="align-items-center col">
mat-flat-button <mat-card *ngIf="hasPositions === true" class="p-0">
(click)="showPositionsButton = false" <mat-card-content>
>Positions</a <gf-positions
> [baseCurrency]="user?.settings?.baseCurrency"
</div> [deviceType]="deviceType"
</div> [locale]="user?.settings?.locale"
[positions]="positions"
<div id="positions-container" class="container positions"> [range]="dateRange"
<div class="row mb-3"> ></gf-positions>
<div class="col"> </mat-card-content>
<mat-card class="p-0"> </mat-card>
<mat-card-content> <div
<gf-positions *ngIf="hasPositions === false"
[baseCurrency]="user?.settings?.baseCurrency" class="d-flex justify-content-center"
[deviceType]="deviceType" >
[locale]="user?.settings?.locale" <gf-no-transactions-info-indicator></gf-no-transactions-info-indicator>
[positions]="positions" </div>
[range]="dateRange" </div>
></gf-positions>
</mat-card-content>
</mat-card>
</div> </div>
</div> </div>
<div class="row"> </mat-tab>
<div class="col-xs-12 col-md-6 mb-3"> <mat-tab>
<mat-card class="h-100"> <ng-template mat-tab-label>
<mat-card-header> <ion-icon name="reader-outline" size="large"></ion-icon>
<mat-card-title i18n>Performance</mat-card-title> </ng-template>
</mat-card-header> <div class="container p-3 positions">
<mat-card-content> <div class="row">
<gf-portfolio-performance <div class="col-xs-12 col-md-6 mb-3">
[baseCurrency]="user?.settings?.baseCurrency" <mat-card class="h-100">
[isLoading]="isLoadingPerformance" <mat-card-header>
[locale]="user?.settings?.locale" <mat-card-title i18n>Performance</mat-card-title>
[performance]="performance" </mat-card-header>
></gf-portfolio-performance> <mat-card-content>
</mat-card-content> <gf-portfolio-performance
</mat-card> [baseCurrency]="user?.settings?.baseCurrency"
</div> [isLoading]="isLoadingPerformance"
<div class="col-xs-12 col-md-6 mb-3"> [locale]="user?.settings?.locale"
<mat-card class="h-100"> [performance]="performance"
<mat-card-header> ></gf-portfolio-performance>
<mat-card-title i18n>Summary</mat-card-title> </mat-card-content>
</mat-card-header> </mat-card>
<mat-card-content> </div>
<gf-portfolio-overview <div class="col-xs-12 col-md-6">
[baseCurrency]="user?.settings?.baseCurrency" <mat-card class="h-100">
[isLoading]="isLoadingOverview" <mat-card-header>
[locale]="user?.settings?.locale" <mat-card-title i18n>Summary</mat-card-title>
[overview]="overview" </mat-card-header>
></gf-portfolio-overview> <mat-card-content>
</mat-card-content> <gf-portfolio-overview
</mat-card> [baseCurrency]="user?.settings?.baseCurrency"
[isLoading]="isLoadingOverview"
[locale]="user?.settings?.locale"
[overview]="overview"
></gf-portfolio-overview>
</mat-card-content>
</mat-card>
</div>
</div> </div>
</div> </div>
</div> </mat-tab>
</ng-container> </mat-tab-group>
<ng-container *ngIf="!hasPositions && historicalDataItems">
<div class="d-flex justify-content-center my-5">
<gf-no-transactions-info-indicator></gf-no-transactions-info-indicator>
</div>
</ng-container>

View File

@ -2,8 +2,10 @@ import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card'; import { MatCardModule } from '@angular/material/card';
import { MatTabsModule } from '@angular/material/tabs';
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
import { GfLineChartModule } from '@ghostfolio/client/components/line-chart/line-chart.module'; import { GfLineChartModule } from '@ghostfolio/client/components/line-chart/line-chart.module';
import { GfNoTransactionsInfoModule } from '@ghostfolio/client/components/no-transactions-info/no-transactions-info.module';
import { GfPerformanceChartDialogModule } from '@ghostfolio/client/components/performance-chart-dialog/performance-chart-dialog.module'; import { GfPerformanceChartDialogModule } from '@ghostfolio/client/components/performance-chart-dialog/performance-chart-dialog.module';
import { GfPortfolioOverviewModule } from '@ghostfolio/client/components/portfolio-overview/portfolio-overview.module'; import { GfPortfolioOverviewModule } from '@ghostfolio/client/components/portfolio-overview/portfolio-overview.module';
import { GfPortfolioPerformanceSummaryModule } from '@ghostfolio/client/components/portfolio-performance-summary/portfolio-performance-summary.module'; import { GfPortfolioPerformanceSummaryModule } from '@ghostfolio/client/components/portfolio-performance-summary/portfolio-performance-summary.module';
@ -20,6 +22,7 @@ import { HomePageComponent } from './home-page.component';
imports: [ imports: [
CommonModule, CommonModule,
GfLineChartModule, GfLineChartModule,
GfNoTransactionsInfoModule,
GfPerformanceChartDialogModule, GfPerformanceChartDialogModule,
GfPortfolioOverviewModule, GfPortfolioOverviewModule,
GfPortfolioPerformanceModule, GfPortfolioPerformanceModule,
@ -29,6 +32,7 @@ import { HomePageComponent } from './home-page.component';
HomePageRoutingModule, HomePageRoutingModule,
MatButtonModule, MatButtonModule,
MatCardModule, MatCardModule,
MatTabsModule,
RouterModule RouterModule
], ],
providers: [], providers: [],

View File

@ -3,58 +3,74 @@
:host { :host {
color: rgb(var(--dark-primary-text)); color: rgb(var(--dark-primary-text));
display: block; display: block;
min-height: 100vh; min-height: calc(100vh - 5rem);
position: relative;
.container { &.with-create-account-container {
&.overview { min-height: calc(100vh - 5rem - 2.5rem);
min-height: calc(100vh - 5rem); }
.button-container { .mat-tab-group {
bottom: 3rem; bottom: 0;
left: 0; left: 0;
right: 0; right: 0;
.mat-flat-button { top: 0;
background-color: rgba(0, 0, 0, $alpha-hover);
border-radius: 2rem; ::ng-deep {
.mat-tab-body-wrapper {
height: 100%;
.container {
&.overview {
.chart-container {
aspect-ratio: 16 / 9;
cursor: pointer;
max-height: 50vh;
// Fallback for aspect-ratio (using padding hack)
@supports not (aspect-ratio: 16 / 9) {
&::before {
float: left;
padding-top: 56.25%;
content: '';
}
&::after {
display: block;
content: '';
clear: both;
}
}
gf-line-chart {
bottom: 0;
left: 0;
position: absolute;
right: 0;
top: 0;
z-index: -1;
}
}
}
&.positions {
min-height: 100%;
}
} }
} }
.chart-container { .mat-tab-header {
aspect-ratio: 16 / 9; border-top: 0;
cursor: pointer;
margin-top: -1rem;
max-height: 50vh;
// Fallback for aspect-ratio (using padding hack) .mat-ink-bar {
@supports not (aspect-ratio: 16 / 9) { visibility: hidden !important;
&::before {
float: left;
padding-top: 56.25%;
content: '';
}
&::after {
display: block;
content: '';
clear: both;
}
} }
gf-line-chart { .mat-tab-label-active {
bottom: 0; color: rgba(var(--palette-primary-500), 1);
left: 0;
position: absolute;
right: 0;
top: 0;
z-index: -1;
} }
} }
} }
&.positions {
padding-top: 5rem;
min-height: calc(100vh - 5rem);
}
} }
::ng-deep { ::ng-deep {

View File

@ -1,65 +1,88 @@
<ng-container *ngIf="hasPositions || !historicalDataItems"> <mat-tab-group
<div class="container overview position-relative"> animationDuration="0ms"
<div class="row"> class="position-absolute"
<div class="chart-container col mr-3"> headerPosition="below"
<gf-line-chart mat-align-tabs="center"
symbol="Performance" >
[historicalDataItems]="historicalDataItems" <mat-tab>
[showLoader]="false" <ng-template mat-tab-label>
[showXAxis]="false" <ion-icon name="analytics-outline" size="large"></ion-icon>
[showYAxis]="false" </ng-template>
></gf-line-chart>
</div>
</div>
<div class="overview-container row mb-5 mt-1">
<div class="col">
<gf-portfolio-performance-summary
class="pb-4"
[baseCurrency]="user?.settings?.baseCurrency"
[isLoading]="isLoadingPerformance"
[locale]="user?.settings?.locale"
[performance]="performance"
[showDetails]="!hasImpersonationId || hasPermissionToReadForeignPortfolio"
></gf-portfolio-performance-summary>
</div>
</div>
<div <div
class="button-container d-flex justify-content-center position-absolute" class="
container
d-flex
flex-column
h-100
justify-content-center
overview
p-3
position-relative
"
> >
<a <div class="row">
*ngIf="showPositionsButton" <div
[routerLink]="['/zen']" class="chart-container d-flex flex-column col justify-content-center"
fragment="positions-container" >
i18n <gf-line-chart
mat-flat-button class="mr-3"
(click)="showPositionsButton = false" symbol="Performance"
>Positions</a [historicalDataItems]="historicalDataItems"
> [showLoader]="false"
</div> [showXAxis]="false"
</div> [showYAxis]="false"
></gf-line-chart>
<div id="positions-container" class="container positions"> <div
<div class="row mb-3"> *ngIf="historicalDataItems?.length === 0"
<div class="col"> class="d-flex justify-content-center"
<mat-card class="p-0"> >
<mat-card-content> <gf-no-transactions-info-indicator></gf-no-transactions-info-indicator>
<gf-positions </div>
[baseCurrency]="user?.settings?.baseCurrency" </div>
[deviceType]="deviceType" </div>
[locale]="user?.settings?.locale" <div class="overview-container row mb-5 mt-1">
[positions]="positions" <div class="col">
[range]="dateRange" <gf-portfolio-performance-summary
></gf-positions> class="pb-4"
</mat-card-content> [baseCurrency]="user?.settings?.baseCurrency"
</mat-card> [isLoading]="isLoadingPerformance"
[locale]="user?.settings?.locale"
[performance]="performance"
[showDetails]="!hasImpersonationId || hasPermissionToReadForeignPortfolio"
></gf-portfolio-performance-summary>
</div>
</div> </div>
</div> </div>
</div> </mat-tab>
</ng-container>
<ng-container *ngIf="!hasPositions && historicalDataItems"> <mat-tab>
<div class="d-flex justify-content-center my-5"> <ng-template mat-tab-label>
<gf-no-transactions-info-indicator></gf-no-transactions-info-indicator> <ion-icon name="wallet-outline" size="large"></ion-icon>
</div> </ng-template>
</ng-container> <div class="container justify-content-center p-3 positions">
<div class="row">
<div class="align-items-center col">
<mat-card *ngIf="hasPositions === true" class="p-0">
<mat-card-content>
<gf-positions
[baseCurrency]="user?.settings?.baseCurrency"
[deviceType]="deviceType"
[locale]="user?.settings?.locale"
[positions]="positions"
[range]="dateRange"
></gf-positions>
</mat-card-content>
</mat-card>
<div
*ngIf="hasPositions === false"
class="d-flex justify-content-center"
>
<div>
<gf-no-transactions-info-indicator></gf-no-transactions-info-indicator>
</div>
</div>
</div>
</div>
</div>
</mat-tab>
</mat-tab-group>

View File

@ -2,6 +2,7 @@ import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card'; import { MatCardModule } from '@angular/material/card';
import { MatTabsModule } from '@angular/material/tabs';
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
import { GfLineChartModule } from '@ghostfolio/client/components/line-chart/line-chart.module'; import { GfLineChartModule } from '@ghostfolio/client/components/line-chart/line-chart.module';
import { GfNoTransactionsInfoModule } from '@ghostfolio/client/components/no-transactions-info/no-transactions-info.module'; import { GfNoTransactionsInfoModule } from '@ghostfolio/client/components/no-transactions-info/no-transactions-info.module';
@ -22,6 +23,7 @@ import { ZenPageComponent } from './zen-page.component';
GfPositionsModule, GfPositionsModule,
MatButtonModule, MatButtonModule,
MatCardModule, MatCardModule,
MatTabsModule,
RouterModule, RouterModule,
ZenPageRoutingModule ZenPageRoutingModule
], ],

View File

@ -3,58 +3,69 @@
:host { :host {
color: rgb(var(--dark-primary-text)); color: rgb(var(--dark-primary-text));
display: block; display: block;
min-height: 100vh; min-height: calc(100vh - 5rem);
position: relative;
.container { .mat-tab-group {
&.overview { bottom: 0;
min-height: calc(100vh - 5rem); left: 0;
right: 0;
top: 0;
.button-container { ::ng-deep {
bottom: 3rem; .mat-tab-body-wrapper {
left: 0; height: 100%;
right: 0;
.mat-flat-button { .container {
background-color: rgba(0, 0, 0, $alpha-hover); &.overview {
border-radius: 2rem; .chart-container {
aspect-ratio: 16 / 9;
max-height: 50vh;
// Fallback for aspect-ratio (using padding hack)
@supports not (aspect-ratio: 16 / 9) {
&::before {
float: left;
padding-top: 56.25%;
content: '';
}
&::after {
display: block;
content: '';
clear: both;
}
}
gf-line-chart {
bottom: 0;
left: 0;
position: absolute;
right: 0;
top: 0;
z-index: -1;
}
}
}
&.positions {
min-height: 100%;
}
} }
} }
.chart-container { .mat-tab-header {
aspect-ratio: 16 / 9; border-top: 0;
margin-top: 3rem;
max-height: 50vh;
// Fallback for aspect-ratio (using padding hack) .mat-ink-bar {
@supports not (aspect-ratio: 16 / 9) { visibility: hidden !important;
&::before {
float: left;
padding-top: 56.25%;
content: '';
}
&::after {
display: block;
content: '';
clear: both;
}
} }
gf-line-chart { .mat-tab-label-active {
bottom: 0; color: rgba(var(--palette-primary-500), 1);
left: 0;
position: absolute;
right: 0;
top: 0;
z-index: -1;
} }
} }
} }
&.positions {
padding-top: 5rem;
min-height: calc(100vh - 5rem);
}
} }
} }