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

* Add tabs

* Update changelog
pull/232/head
Thomas 3 years ago committed by GitHub
parent 6dbdf23a68
commit 40696b425e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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/),
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
### Added

@ -9,7 +9,7 @@
</header>
<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="col-md-8 offset-md-2 text-center">
<a class="text-center" [routerLink]="['/']">

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

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

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

@ -2,8 +2,10 @@ import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatTabsModule } from '@angular/material/tabs';
import { RouterModule } from '@angular/router';
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 { GfPortfolioOverviewModule } from '@ghostfolio/client/components/portfolio-overview/portfolio-overview.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: [
CommonModule,
GfLineChartModule,
GfNoTransactionsInfoModule,
GfPerformanceChartDialogModule,
GfPortfolioOverviewModule,
GfPortfolioPerformanceModule,
@ -29,6 +32,7 @@ import { HomePageComponent } from './home-page.component';
HomePageRoutingModule,
MatButtonModule,
MatCardModule,
MatTabsModule,
RouterModule
],
providers: [],

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

@ -1,65 +1,88 @@
<ng-container *ngIf="hasPositions || !historicalDataItems">
<div class="container overview position-relative">
<div class="row">
<div class="chart-container col mr-3">
<gf-line-chart
symbol="Performance"
[historicalDataItems]="historicalDataItems"
[showLoader]="false"
[showXAxis]="false"
[showYAxis]="false"
></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>
<mat-tab-group
animationDuration="0ms"
class="position-absolute"
headerPosition="below"
mat-align-tabs="center"
>
<mat-tab>
<ng-template mat-tab-label>
<ion-icon name="analytics-outline" size="large"></ion-icon>
</ng-template>
<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
*ngIf="showPositionsButton"
[routerLink]="['/zen']"
fragment="positions-container"
i18n
mat-flat-button
(click)="showPositionsButton = false"
>Positions</a
>
<div class="row">
<div
class="chart-container d-flex flex-column col justify-content-center"
>
<gf-line-chart
class="mr-3"
symbol="Performance"
[historicalDataItems]="historicalDataItems"
[showLoader]="false"
[showXAxis]="false"
[showYAxis]="false"
></gf-line-chart>
<div
*ngIf="historicalDataItems?.length === 0"
class="d-flex justify-content-center"
>
<gf-no-transactions-info-indicator></gf-no-transactions-info-indicator>
</div>
</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>
</mat-tab>
<div id="positions-container" class="container positions">
<div class="row mb-3">
<div class="col">
<mat-card 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>
<mat-tab>
<ng-template mat-tab-label>
<ion-icon name="wallet-outline" size="large"></ion-icon>
</ng-template>
<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>
</div>
</ng-container>
<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>
</mat-tab>
</mat-tab-group>

@ -2,6 +2,7 @@ import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatTabsModule } from '@angular/material/tabs';
import { RouterModule } from '@angular/router';
import { GfLineChartModule } from '@ghostfolio/client/components/line-chart/line-chart.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,
MatButtonModule,
MatCardModule,
MatTabsModule,
RouterModule,
ZenPageRoutingModule
],

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

Loading…
Cancel
Save