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 {