From d0112968e8c3b9a8e6aa1014d86b4af1b6abf101 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 16 Sep 2023 14:40:05 +0200 Subject: [PATCH] Feature/introduce sidebar navigation on desktop (#2340) * Introduce sidebar navigation on desktop * Update changelog --- CHANGELOG.md | 6 +++ .../app/pages/about/about-page.component.ts | 8 ++- .../src/app/pages/about/about-page.html | 5 +- .../src/app/pages/about/about-page.scss | 21 -------- .../app/pages/admin/admin-page.component.ts | 10 +++- .../src/app/pages/admin/admin-page.html | 5 +- .../src/app/pages/admin/admin-page.scss | 21 -------- .../src/app/pages/home/home-page.component.ts | 8 ++- apps/client/src/app/pages/home/home-page.html | 5 +- apps/client/src/app/pages/home/home-page.scss | 21 -------- .../portfolio/portfolio-page.component.ts | 8 ++- .../app/pages/portfolio/portfolio-page.html | 5 +- .../app/pages/portfolio/portfolio-page.scss | 21 -------- .../src/app/pages/zen/zen-page.component.ts | 34 +++++-------- apps/client/src/app/pages/zen/zen-page.html | 5 +- apps/client/src/app/pages/zen/zen-page.scss | 21 -------- apps/client/src/styles.scss | 50 ++++++++++++++++++- 17 files changed, 117 insertions(+), 137 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 951c7b05..11b36107 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 + +### Added + +- Introduced a sidebar navigation on desktop + ## 2.1.0 - 2023-09-15 ### Added diff --git a/apps/client/src/app/pages/about/about-page.component.ts b/apps/client/src/app/pages/about/about-page.component.ts index ef000d49..6d9887dd 100644 --- a/apps/client/src/app/pages/about/about-page.component.ts +++ b/apps/client/src/app/pages/about/about-page.component.ts @@ -9,10 +9,12 @@ import { DataService } from '@ghostfolio/client/services/data.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { TabConfiguration, User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; +import { DeviceDetectorService } from 'ngx-device-detector'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; @Component({ + host: { class: 'page with-tabs' }, selector: 'gf-about-page', styleUrls: ['./about-page.scss'], templateUrl: './about-page.html' @@ -22,6 +24,7 @@ export class AboutPageComponent implements OnDestroy, OnInit { return this.hasMessage; } + public deviceType: string; public hasMessage: boolean; public hasPermissionForSubscription: boolean; public tabs: TabConfiguration[] = []; @@ -32,6 +35,7 @@ export class AboutPageComponent implements OnDestroy, OnInit { public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private deviceService: DeviceDetectorService, private userService: UserService ) { const { globalPermissions, systemMessage } = this.dataService.fetchInfo(); @@ -88,7 +92,9 @@ export class AboutPageComponent implements OnDestroy, OnInit { }); } - public ngOnInit() {} + public ngOnInit() { + this.deviceType = this.deviceService.getDeviceInfo().deviceType; + } public ngOnDestroy() { this.unsubscribeSubject.next(); diff --git a/apps/client/src/app/pages/about/about-page.html b/apps/client/src/app/pages/about/about-page.html index ce1d8485..014f68b9 100644 --- a/apps/client/src/app/pages/about/about-page.html +++ b/apps/client/src/app/pages/about/about-page.html @@ -14,7 +14,10 @@ [routerLink]="tab.path" [routerLinkActiveOptions]="{ exact: true }" > - +
{{ tab.label }}
diff --git a/apps/client/src/app/pages/about/about-page.scss b/apps/client/src/app/pages/about/about-page.scss index daeb6fc9..6a0b7485 100644 --- a/apps/client/src/app/pages/about/about-page.scss +++ b/apps/client/src/app/pages/about/about-page.scss @@ -2,27 +2,6 @@ :host { color: rgb(var(--dark-primary-text)); - display: flex; - flex-direction: column; - height: calc(100vh - 5rem); - overflow-y: auto; - - padding-bottom: env(safe-area-inset-bottom); - padding-bottom: constant(safe-area-inset-bottom); - - ::ng-deep { - .mat-mdc-tab-link-container { - --mat-tab-header-active-focus-indicator-color: transparent; - --mat-tab-header-active-hover-indicator-color: transparent; - --mdc-tab-indicator-active-indicator-color: transparent; - - .mat-mdc-tab-link { - &:hover { - opacity: 0.75; - } - } - } - } } :host-context(.is-dark-theme) { diff --git a/apps/client/src/app/pages/admin/admin-page.component.ts b/apps/client/src/app/pages/admin/admin-page.component.ts index c9563072..6ba5d0ac 100644 --- a/apps/client/src/app/pages/admin/admin-page.component.ts +++ b/apps/client/src/app/pages/admin/admin-page.component.ts @@ -1,9 +1,11 @@ import { Component, HostBinding, OnDestroy, OnInit } from '@angular/core'; import { DataService } from '@ghostfolio/client/services/data.service'; import { TabConfiguration } from '@ghostfolio/common/interfaces'; +import { DeviceDetectorService } from 'ngx-device-detector'; import { Subject } from 'rxjs'; @Component({ + host: { class: 'page with-tabs' }, selector: 'gf-admin-page', styleUrls: ['./admin-page.scss'], templateUrl: './admin-page.html' @@ -13,18 +15,24 @@ export class AdminPageComponent implements OnDestroy, OnInit { return this.hasMessage; } + public deviceType: string; public hasMessage: boolean; public tabs: TabConfiguration[] = []; private unsubscribeSubject = new Subject(); - public constructor(private dataService: DataService) { + public constructor( + private dataService: DataService, + private deviceService: DeviceDetectorService + ) { const { systemMessage } = this.dataService.fetchInfo(); this.hasMessage = !!systemMessage; } public ngOnInit() { + this.deviceType = this.deviceService.getDeviceInfo().deviceType; + this.tabs = [ { iconName: 'reader-outline', diff --git a/apps/client/src/app/pages/admin/admin-page.html b/apps/client/src/app/pages/admin/admin-page.html index ce1d8485..014f68b9 100644 --- a/apps/client/src/app/pages/admin/admin-page.html +++ b/apps/client/src/app/pages/admin/admin-page.html @@ -14,7 +14,10 @@ [routerLink]="tab.path" [routerLinkActiveOptions]="{ exact: true }" > - +
{{ tab.label }}
diff --git a/apps/client/src/app/pages/admin/admin-page.scss b/apps/client/src/app/pages/admin/admin-page.scss index daeb6fc9..6a0b7485 100644 --- a/apps/client/src/app/pages/admin/admin-page.scss +++ b/apps/client/src/app/pages/admin/admin-page.scss @@ -2,27 +2,6 @@ :host { color: rgb(var(--dark-primary-text)); - display: flex; - flex-direction: column; - height: calc(100vh - 5rem); - overflow-y: auto; - - padding-bottom: env(safe-area-inset-bottom); - padding-bottom: constant(safe-area-inset-bottom); - - ::ng-deep { - .mat-mdc-tab-link-container { - --mat-tab-header-active-focus-indicator-color: transparent; - --mat-tab-header-active-hover-indicator-color: transparent; - --mdc-tab-indicator-active-indicator-color: transparent; - - .mat-mdc-tab-link { - &:hover { - opacity: 0.75; - } - } - } - } } :host-context(.is-dark-theme) { diff --git a/apps/client/src/app/pages/home/home-page.component.ts b/apps/client/src/app/pages/home/home-page.component.ts index 77c31839..13904e03 100644 --- a/apps/client/src/app/pages/home/home-page.component.ts +++ b/apps/client/src/app/pages/home/home-page.component.ts @@ -9,10 +9,12 @@ import { DataService } from '@ghostfolio/client/services/data.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { TabConfiguration, User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; +import { DeviceDetectorService } from 'ngx-device-detector'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; @Component({ + host: { class: 'page with-tabs' }, selector: 'gf-home-page', styleUrls: ['./home-page.scss'], templateUrl: './home-page.html' @@ -22,6 +24,7 @@ export class HomePageComponent implements OnDestroy, OnInit { return this.hasMessage; } + public deviceType: string; public hasMessage: boolean; public hasPermissionToAccessFearAndGreedIndex: boolean; public tabs: TabConfiguration[] = []; @@ -32,6 +35,7 @@ export class HomePageComponent implements OnDestroy, OnInit { public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private deviceService: DeviceDetectorService, private userService: UserService ) { const { globalPermissions, systemMessage } = this.dataService.fetchInfo(); @@ -81,7 +85,9 @@ export class HomePageComponent implements OnDestroy, OnInit { }); } - public ngOnInit() {} + public ngOnInit() { + this.deviceType = this.deviceService.getDeviceInfo().deviceType; + } public ngOnDestroy() { this.unsubscribeSubject.next(); diff --git a/apps/client/src/app/pages/home/home-page.html b/apps/client/src/app/pages/home/home-page.html index ce1d8485..014f68b9 100644 --- a/apps/client/src/app/pages/home/home-page.html +++ b/apps/client/src/app/pages/home/home-page.html @@ -14,7 +14,10 @@ [routerLink]="tab.path" [routerLinkActiveOptions]="{ exact: true }" > - +
{{ tab.label }}
diff --git a/apps/client/src/app/pages/home/home-page.scss b/apps/client/src/app/pages/home/home-page.scss index daeb6fc9..6a0b7485 100644 --- a/apps/client/src/app/pages/home/home-page.scss +++ b/apps/client/src/app/pages/home/home-page.scss @@ -2,27 +2,6 @@ :host { color: rgb(var(--dark-primary-text)); - display: flex; - flex-direction: column; - height: calc(100vh - 5rem); - overflow-y: auto; - - padding-bottom: env(safe-area-inset-bottom); - padding-bottom: constant(safe-area-inset-bottom); - - ::ng-deep { - .mat-mdc-tab-link-container { - --mat-tab-header-active-focus-indicator-color: transparent; - --mat-tab-header-active-hover-indicator-color: transparent; - --mdc-tab-indicator-active-indicator-color: transparent; - - .mat-mdc-tab-link { - &:hover { - opacity: 0.75; - } - } - } - } } :host-context(.is-dark-theme) { diff --git a/apps/client/src/app/pages/portfolio/portfolio-page.component.ts b/apps/client/src/app/pages/portfolio/portfolio-page.component.ts index 2244e7af..8d4b3b62 100644 --- a/apps/client/src/app/pages/portfolio/portfolio-page.component.ts +++ b/apps/client/src/app/pages/portfolio/portfolio-page.component.ts @@ -13,10 +13,12 @@ import { User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; +import { DeviceDetectorService } from 'ngx-device-detector'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; @Component({ + host: { class: 'page with-tabs' }, selector: 'gf-portfolio-page', styleUrls: ['./portfolio-page.scss'], templateUrl: './portfolio-page.html' @@ -26,6 +28,7 @@ export class PortfolioPageComponent implements OnDestroy, OnInit { return this.hasMessage; } + public deviceType: string; public hasMessage: boolean; public info: InfoItem; public tabs: TabConfiguration[] = []; @@ -36,6 +39,7 @@ export class PortfolioPageComponent implements OnDestroy, OnInit { public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private deviceService: DeviceDetectorService, private userService: UserService ) { this.info = this.dataService.fetchInfo(); @@ -84,7 +88,9 @@ export class PortfolioPageComponent implements OnDestroy, OnInit { }); } - public ngOnInit() {} + public ngOnInit() { + this.deviceType = this.deviceService.getDeviceInfo().deviceType; + } public ngOnDestroy() { this.unsubscribeSubject.next(); diff --git a/apps/client/src/app/pages/portfolio/portfolio-page.html b/apps/client/src/app/pages/portfolio/portfolio-page.html index ce1d8485..014f68b9 100644 --- a/apps/client/src/app/pages/portfolio/portfolio-page.html +++ b/apps/client/src/app/pages/portfolio/portfolio-page.html @@ -14,7 +14,10 @@ [routerLink]="tab.path" [routerLinkActiveOptions]="{ exact: true }" > - +
{{ tab.label }}
diff --git a/apps/client/src/app/pages/portfolio/portfolio-page.scss b/apps/client/src/app/pages/portfolio/portfolio-page.scss index daeb6fc9..6a0b7485 100644 --- a/apps/client/src/app/pages/portfolio/portfolio-page.scss +++ b/apps/client/src/app/pages/portfolio/portfolio-page.scss @@ -2,27 +2,6 @@ :host { color: rgb(var(--dark-primary-text)); - display: flex; - flex-direction: column; - height: calc(100vh - 5rem); - overflow-y: auto; - - padding-bottom: env(safe-area-inset-bottom); - padding-bottom: constant(safe-area-inset-bottom); - - ::ng-deep { - .mat-mdc-tab-link-container { - --mat-tab-header-active-focus-indicator-color: transparent; - --mat-tab-header-active-hover-indicator-color: transparent; - --mdc-tab-indicator-active-indicator-color: transparent; - - .mat-mdc-tab-link { - &:hover { - opacity: 0.75; - } - } - } - } } :host-context(.is-dark-theme) { diff --git a/apps/client/src/app/pages/zen/zen-page.component.ts b/apps/client/src/app/pages/zen/zen-page.component.ts index 9f769e28..ab164af4 100644 --- a/apps/client/src/app/pages/zen/zen-page.component.ts +++ b/apps/client/src/app/pages/zen/zen-page.component.ts @@ -1,33 +1,27 @@ -import { ViewportScroller } from '@angular/common'; -import { - AfterViewInit, - ChangeDetectorRef, - Component, - OnDestroy, - OnInit -} from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; +import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { TabConfiguration, User } from '@ghostfolio/common/interfaces'; +import { DeviceDetectorService } from 'ngx-device-detector'; import { Subject } from 'rxjs'; -import { first, takeUntil } from 'rxjs/operators'; +import { takeUntil } from 'rxjs/operators'; @Component({ + host: { class: 'page with-tabs' }, selector: 'gf-zen-page', - templateUrl: './zen-page.html', - styleUrls: ['./zen-page.scss'] + styleUrls: ['./zen-page.scss'], + templateUrl: './zen-page.html' }) -export class ZenPageComponent implements AfterViewInit, OnDestroy, OnInit { +export class ZenPageComponent implements OnDestroy, OnInit { + public deviceType: string; public tabs: TabConfiguration[] = []; public user: User; private unsubscribeSubject = new Subject(); public constructor( - private route: ActivatedRoute, private changeDetectorRef: ChangeDetectorRef, - private userService: UserService, - private viewportScroller: ViewportScroller + private deviceService: DeviceDetectorService, + private userService: UserService ) { this.userService.stateChanged .pipe(takeUntil(this.unsubscribeSubject)) @@ -52,12 +46,8 @@ export class ZenPageComponent implements AfterViewInit, OnDestroy, OnInit { }); } - public ngOnInit() {} - - public ngAfterViewInit(): void { - this.route.fragment - .pipe(first()) - .subscribe((fragment) => this.viewportScroller.scrollToAnchor(fragment)); + public ngOnInit() { + this.deviceType = this.deviceService.getDeviceInfo().deviceType; } public ngOnDestroy() { diff --git a/apps/client/src/app/pages/zen/zen-page.html b/apps/client/src/app/pages/zen/zen-page.html index ce1d8485..014f68b9 100644 --- a/apps/client/src/app/pages/zen/zen-page.html +++ b/apps/client/src/app/pages/zen/zen-page.html @@ -14,7 +14,10 @@ [routerLink]="tab.path" [routerLinkActiveOptions]="{ exact: true }" > - +
{{ tab.label }}
diff --git a/apps/client/src/app/pages/zen/zen-page.scss b/apps/client/src/app/pages/zen/zen-page.scss index daeb6fc9..6a0b7485 100644 --- a/apps/client/src/app/pages/zen/zen-page.scss +++ b/apps/client/src/app/pages/zen/zen-page.scss @@ -2,27 +2,6 @@ :host { color: rgb(var(--dark-primary-text)); - display: flex; - flex-direction: column; - height: calc(100vh - 5rem); - overflow-y: auto; - - padding-bottom: env(safe-area-inset-bottom); - padding-bottom: constant(safe-area-inset-bottom); - - ::ng-deep { - .mat-mdc-tab-link-container { - --mat-tab-header-active-focus-indicator-color: transparent; - --mat-tab-header-active-hover-indicator-color: transparent; - --mdc-tab-indicator-active-indicator-color: transparent; - - .mat-mdc-tab-link { - &:hover { - opacity: 0.75; - } - } - } - } } :host-context(.is-dark-theme) { diff --git a/apps/client/src/styles.scss b/apps/client/src/styles.scss index c7624c83..88a7f9dc 100644 --- a/apps/client/src/styles.scss +++ b/apps/client/src/styles.scss @@ -274,6 +274,16 @@ body { } } + .page { + &.with-tabs { + .mat-mdc-tab-nav-bar { + --mat-tab-header-inactive-label-text-color: rgba( + var(--light-primary-text) + ); + } + } + } + .svgMap-tooltip { background: var(--dark-background); @@ -455,7 +465,45 @@ ngx-skeleton-loader { } .page { - padding-bottom: 5rem; + display: flex; + flex-direction: column; + overflow-y: auto; + + &:not(.with-tabs) { + padding-bottom: 5rem; + } + + &.with-tabs { + height: calc(100vh - 5rem); + padding-bottom: env(safe-area-inset-bottom); + padding-bottom: constant(safe-area-inset-bottom); + + .mat-mdc-tab-nav-bar { + --mat-tab-header-active-focus-indicator-color: transparent; + --mat-tab-header-active-hover-indicator-color: transparent; + --mat-tab-header-inactive-label-text-color: rgba( + var(--dark-primary-text) + ); + --mdc-tab-indicator-active-indicator-color: transparent; + } + + @media (min-width: 576px) { + flex-direction: row-reverse; + + .mat-mdc-tab-header { + width: 12rem; + --mdc-secondary-navigation-tab-container-height: 2rem; + + .mat-mdc-tab-links { + flex-direction: column; + + .mat-mdc-tab-link { + justify-content: flex-start; + } + } + } + } + } } .svgMap-tooltip {