From ceea375227e8ef3adbc4a01d92f11f40bf481110 Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Fri, 15 May 2026 15:30:23 +0300
Subject: [PATCH] Task/extract page tabs to dedicated component (#6797)
* Extract page tabs
* Update changelog
---
CHANGELOG.md | 4 ++
.../app/pages/about/about-page.component.ts | 29 +++-----
.../src/app/pages/about/about-page.html | 31 +-------
.../app/pages/admin/admin-page.component.ts | 16 ++---
.../src/app/pages/admin/admin-page.html | 31 +-------
.../src/app/pages/faq/faq-page.component.ts | 26 +++----
apps/client/src/app/pages/faq/faq-page.html | 31 +-------
.../src/app/pages/home/home-page.component.ts | 18 ++---
apps/client/src/app/pages/home/home-page.html | 31 +-------
.../portfolio/portfolio-page.component.ts | 26 +++----
.../app/pages/portfolio/portfolio-page.html | 31 +-------
.../resources/resources-page.component.ts | 22 +++---
.../app/pages/resources/resources-page.html | 31 +-------
.../user-account-page.component.ts | 29 +++-----
.../pages/user-account/user-account-page.html | 31 +-------
.../src/app/pages/zen/zen-page.component.ts | 27 +++----
apps/client/src/app/pages/zen/zen-page.html | 31 +-------
apps/client/src/styles.scss | 49 -------------
apps/client/src/styles/theme.scss | 27 -------
libs/common/src/lib/interfaces/index.ts | 2 -
libs/ui/src/lib/page-tabs/index.ts | 2 +
.../lib/page-tabs/interfaces/interfaces.ts} | 0
.../lib/page-tabs/page-tabs.component.html | 30 ++++++++
.../lib/page-tabs/page-tabs.component.scss | 70 +++++++++++++++++++
.../src/lib/page-tabs/page-tabs.component.ts | 30 ++++++++
25 files changed, 204 insertions(+), 451 deletions(-)
create mode 100644 libs/ui/src/lib/page-tabs/index.ts
rename libs/{common/src/lib/interfaces/tab-configuration.interface.ts => ui/src/lib/page-tabs/interfaces/interfaces.ts} (100%)
create mode 100644 libs/ui/src/lib/page-tabs/page-tabs.component.html
create mode 100644 libs/ui/src/lib/page-tabs/page-tabs.component.scss
create mode 100644 libs/ui/src/lib/page-tabs/page-tabs.component.ts
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d7676efee..e8a33af2a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
+### Changed
+
+- Extracted the page tabs to a reusable component
+
### Fixed
- Resolved an issue with the cash balance calculation of an account for `SELL` activities to ensure fees are correctly subtracted
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 b23377f3c..fb632a586 100644
--- a/apps/client/src/app/pages/about/about-page.component.ts
+++ b/apps/client/src/app/pages/about/about-page.component.ts
@@ -1,20 +1,15 @@
import { UserService } from '@ghostfolio/client/services/user/user.service';
-import { TabConfiguration, User } from '@ghostfolio/common/interfaces';
+import { User } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { publicRoutes } from '@ghostfolio/common/routes/routes';
+import {
+ GfPageTabsComponent,
+ TabConfiguration
+} from '@ghostfolio/ui/page-tabs';
import { DataService } from '@ghostfolio/ui/services';
-import {
- ChangeDetectorRef,
- Component,
- CUSTOM_ELEMENTS_SCHEMA,
- DestroyRef,
- OnInit
-} from '@angular/core';
+import { ChangeDetectorRef, Component, DestroyRef } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
-import { MatTabsModule } from '@angular/material/tabs';
-import { RouterModule } from '@angular/router';
-import { IonIcon } from '@ionic/angular/standalone';
import { addIcons } from 'ionicons';
import {
documentTextOutline,
@@ -24,18 +19,15 @@ import {
shieldCheckmarkOutline,
sparklesOutline
} from 'ionicons/icons';
-import { DeviceDetectorService } from 'ngx-device-detector';
@Component({
host: { class: 'page has-tabs' },
- imports: [IonIcon, MatTabsModule, RouterModule],
- schemas: [CUSTOM_ELEMENTS_SCHEMA],
+ imports: [GfPageTabsComponent],
selector: 'gf-about-page',
styleUrls: ['./about-page.scss'],
templateUrl: './about-page.html'
})
-export class AboutPageComponent implements OnInit {
- public deviceType: string;
+export class AboutPageComponent {
public hasPermissionForSubscription: boolean;
public tabs: TabConfiguration[] = [];
public user: User;
@@ -44,7 +36,6 @@ export class AboutPageComponent implements OnInit {
private changeDetectorRef: ChangeDetectorRef,
private dataService: DataService,
private destroyRef: DestroyRef,
- private deviceDetectorService: DeviceDetectorService,
private userService: UserService
) {
const { globalPermissions } = this.dataService.fetchInfo();
@@ -112,8 +103,4 @@ export class AboutPageComponent implements OnInit {
sparklesOutline
});
}
-
- public ngOnInit() {
- this.deviceType = this.deviceDetectorService.getDeviceInfo().deviceType;
- }
}
diff --git a/apps/client/src/app/pages/about/about-page.html b/apps/client/src/app/pages/about/about-page.html
index bd1338774..5d1bdce9b 100644
--- a/apps/client/src/app/pages/about/about-page.html
+++ b/apps/client/src/app/pages/about/about-page.html
@@ -1,30 +1 @@
-
-
-
-
-
+
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 8ec094915..6b653efb0 100644
--- a/apps/client/src/app/pages/admin/admin-page.component.ts
+++ b/apps/client/src/app/pages/admin/admin-page.component.ts
@@ -1,10 +1,10 @@
-import { TabConfiguration } from '@ghostfolio/common/interfaces';
import { internalRoutes } from '@ghostfolio/common/routes/routes';
+import {
+ GfPageTabsComponent,
+ TabConfiguration
+} from '@ghostfolio/ui/page-tabs';
import { Component, OnInit } from '@angular/core';
-import { MatTabsModule } from '@angular/material/tabs';
-import { RouterModule } from '@angular/router';
-import { IonIcon } from '@ionic/angular/standalone';
import { addIcons } from 'ionicons';
import {
flashOutline,
@@ -13,20 +13,18 @@ import {
serverOutline,
settingsOutline
} from 'ionicons/icons';
-import { DeviceDetectorService } from 'ngx-device-detector';
@Component({
host: { class: 'page has-tabs' },
- imports: [IonIcon, MatTabsModule, RouterModule],
+ imports: [GfPageTabsComponent],
selector: 'gf-admin-page',
styleUrls: ['./admin-page.scss'],
templateUrl: './admin-page.html'
})
export class AdminPageComponent implements OnInit {
- public deviceType: string;
public tabs: TabConfiguration[] = [];
- public constructor(private deviceDetectorService: DeviceDetectorService) {
+ public constructor() {
addIcons({
flashOutline,
peopleOutline,
@@ -37,8 +35,6 @@ export class AdminPageComponent implements OnInit {
}
public ngOnInit() {
- this.deviceType = this.deviceDetectorService.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 a5c5ed7e9..5d1bdce9b 100644
--- a/apps/client/src/app/pages/admin/admin-page.html
+++ b/apps/client/src/app/pages/admin/admin-page.html
@@ -1,30 +1 @@
-
-
-
-
-
+
diff --git a/apps/client/src/app/pages/faq/faq-page.component.ts b/apps/client/src/app/pages/faq/faq-page.component.ts
index 8ae074bee..6dabdb5e2 100644
--- a/apps/client/src/app/pages/faq/faq-page.component.ts
+++ b/apps/client/src/app/pages/faq/faq-page.component.ts
@@ -1,33 +1,27 @@
-import { TabConfiguration } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { publicRoutes } from '@ghostfolio/common/routes/routes';
+import {
+ GfPageTabsComponent,
+ TabConfiguration
+} from '@ghostfolio/ui/page-tabs';
import { DataService } from '@ghostfolio/ui/services';
-import { CUSTOM_ELEMENTS_SCHEMA, Component, OnInit } from '@angular/core';
-import { MatTabsModule } from '@angular/material/tabs';
-import { RouterModule } from '@angular/router';
-import { IonIcon } from '@ionic/angular/standalone';
+import { Component } from '@angular/core';
import { addIcons } from 'ionicons';
import { cloudyOutline, readerOutline, serverOutline } from 'ionicons/icons';
-import { DeviceDetectorService } from 'ngx-device-detector';
@Component({
host: { class: 'page has-tabs' },
- imports: [IonIcon, MatTabsModule, RouterModule],
- schemas: [CUSTOM_ELEMENTS_SCHEMA],
+ imports: [GfPageTabsComponent],
selector: 'gf-faq-page',
styleUrls: ['./faq-page.scss'],
templateUrl: './faq-page.html'
})
-export class GfFaqPageComponent implements OnInit {
- public deviceType: string;
+export class GfFaqPageComponent {
public hasPermissionForSubscription: boolean;
public tabs: TabConfiguration[] = [];
- public constructor(
- private dataService: DataService,
- private deviceDetectorService: DeviceDetectorService
- ) {
+ public constructor(private dataService: DataService) {
const { globalPermissions } = this.dataService.fetchInfo();
this.hasPermissionForSubscription = hasPermission(
@@ -56,8 +50,4 @@ export class GfFaqPageComponent implements OnInit {
addIcons({ cloudyOutline, readerOutline, serverOutline });
}
-
- public ngOnInit() {
- this.deviceType = this.deviceDetectorService.getDeviceInfo().deviceType;
- }
}
diff --git a/apps/client/src/app/pages/faq/faq-page.html b/apps/client/src/app/pages/faq/faq-page.html
index bd1338774..5d1bdce9b 100644
--- a/apps/client/src/app/pages/faq/faq-page.html
+++ b/apps/client/src/app/pages/faq/faq-page.html
@@ -1,30 +1 @@
-
-
-
-
-
+
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 958428331..453a79a52 100644
--- a/apps/client/src/app/pages/home/home-page.component.ts
+++ b/apps/client/src/app/pages/home/home-page.component.ts
@@ -1,20 +1,20 @@
import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service';
import { UserService } from '@ghostfolio/client/services/user/user.service';
-import { TabConfiguration, User } from '@ghostfolio/common/interfaces';
+import { User } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { internalRoutes } from '@ghostfolio/common/routes/routes';
+import {
+ GfPageTabsComponent,
+ TabConfiguration
+} from '@ghostfolio/ui/page-tabs';
import {
ChangeDetectorRef,
Component,
- CUSTOM_ELEMENTS_SCHEMA,
DestroyRef,
OnInit
} from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
-import { MatTabsModule } from '@angular/material/tabs';
-import { RouterModule } from '@angular/router';
-import { IonIcon } from '@ionic/angular/standalone';
import { addIcons } from 'ionicons';
import {
albumsOutline,
@@ -23,18 +23,15 @@ import {
newspaperOutline,
readerOutline
} from 'ionicons/icons';
-import { DeviceDetectorService } from 'ngx-device-detector';
@Component({
host: { class: 'page has-tabs' },
- imports: [IonIcon, MatTabsModule, RouterModule],
- schemas: [CUSTOM_ELEMENTS_SCHEMA],
+ imports: [GfPageTabsComponent],
selector: 'gf-home-page',
styleUrls: ['./home-page.scss'],
templateUrl: './home-page.html'
})
export class GfHomePageComponent implements OnInit {
- public deviceType: string;
public hasImpersonationId: boolean;
public tabs: TabConfiguration[] = [];
public user: User;
@@ -42,7 +39,6 @@ export class GfHomePageComponent implements OnInit {
public constructor(
private changeDetectorRef: ChangeDetectorRef,
private destroyRef: DestroyRef,
- private deviceDetectorService: DeviceDetectorService,
private impersonationStorageService: ImpersonationStorageService,
private userService: UserService
) {
@@ -104,8 +100,6 @@ export class GfHomePageComponent implements OnInit {
}
public ngOnInit() {
- this.deviceType = this.deviceDetectorService.getDeviceInfo().deviceType;
-
this.impersonationStorageService
.onChangeHasImpersonation()
.pipe(takeUntilDestroyed(this.destroyRef))
diff --git a/apps/client/src/app/pages/home/home-page.html b/apps/client/src/app/pages/home/home-page.html
index bd1338774..5d1bdce9b 100644
--- a/apps/client/src/app/pages/home/home-page.html
+++ b/apps/client/src/app/pages/home/home-page.html
@@ -1,30 +1 @@
-
-
-
-
-
+
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 dca39c4a6..00fb3242b 100644
--- a/apps/client/src/app/pages/portfolio/portfolio-page.component.ts
+++ b/apps/client/src/app/pages/portfolio/portfolio-page.component.ts
@@ -1,16 +1,13 @@
import { UserService } from '@ghostfolio/client/services/user/user.service';
-import { TabConfiguration, User } from '@ghostfolio/common/interfaces';
+import { User } from '@ghostfolio/common/interfaces';
import { internalRoutes } from '@ghostfolio/common/routes/routes';
-
import {
- ChangeDetectorRef,
- Component,
- DestroyRef,
- OnInit
-} from '@angular/core';
+ GfPageTabsComponent,
+ TabConfiguration
+} from '@ghostfolio/ui/page-tabs';
+
+import { ChangeDetectorRef, Component, DestroyRef } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
-import { MatTabsModule } from '@angular/material/tabs';
-import { RouterModule } from '@angular/router';
import { addIcons } from 'ionicons';
import {
analyticsOutline,
@@ -19,24 +16,21 @@ import {
scanOutline,
swapVerticalOutline
} from 'ionicons/icons';
-import { DeviceDetectorService } from 'ngx-device-detector';
@Component({
host: { class: 'page has-tabs' },
- imports: [MatTabsModule, RouterModule],
+ imports: [GfPageTabsComponent],
selector: 'gf-portfolio-page',
styleUrls: ['./portfolio-page.scss'],
templateUrl: './portfolio-page.html'
})
-export class PortfolioPageComponent implements OnInit {
- public deviceType: string;
+export class PortfolioPageComponent {
public tabs: TabConfiguration[] = [];
public user: User;
public constructor(
private changeDetectorRef: ChangeDetectorRef,
private destroyRef: DestroyRef,
- private deviceDetectorService: DeviceDetectorService,
private userService: UserService
) {
this.userService.stateChanged
@@ -86,8 +80,4 @@ export class PortfolioPageComponent implements OnInit {
swapVerticalOutline
});
}
-
- public ngOnInit() {
- this.deviceType = this.deviceDetectorService.getDeviceInfo().deviceType;
- }
}
diff --git a/apps/client/src/app/pages/portfolio/portfolio-page.html b/apps/client/src/app/pages/portfolio/portfolio-page.html
index bd1338774..5d1bdce9b 100644
--- a/apps/client/src/app/pages/portfolio/portfolio-page.html
+++ b/apps/client/src/app/pages/portfolio/portfolio-page.html
@@ -1,30 +1 @@
-
-
-
-
-
+
diff --git a/apps/client/src/app/pages/resources/resources-page.component.ts b/apps/client/src/app/pages/resources/resources-page.component.ts
index 016f92fa8..faba06f28 100644
--- a/apps/client/src/app/pages/resources/resources-page.component.ts
+++ b/apps/client/src/app/pages/resources/resources-page.component.ts
@@ -1,10 +1,10 @@
-import { TabConfiguration } from '@ghostfolio/common/interfaces';
import { publicRoutes } from '@ghostfolio/common/routes/routes';
+import {
+ GfPageTabsComponent,
+ TabConfiguration
+} from '@ghostfolio/ui/page-tabs';
-import { Component, OnInit } from '@angular/core';
-import { MatTabsModule } from '@angular/material/tabs';
-import { RouterModule } from '@angular/router';
-import { IonIcon } from '@ionic/angular/standalone';
+import { Component } from '@angular/core';
import { addIcons } from 'ionicons';
import {
bookOutline,
@@ -12,17 +12,15 @@ import {
newspaperOutline,
readerOutline
} from 'ionicons/icons';
-import { DeviceDetectorService } from 'ngx-device-detector';
@Component({
host: { class: 'page has-tabs' },
- imports: [IonIcon, MatTabsModule, RouterModule],
+ imports: [GfPageTabsComponent],
selector: 'gf-resources-page',
styleUrls: ['./resources-page.scss'],
templateUrl: './resources-page.html'
})
-export class ResourcesPageComponent implements OnInit {
- public deviceType: string;
+export class ResourcesPageComponent {
public tabs: TabConfiguration[] = [
{
iconName: 'reader-outline',
@@ -46,11 +44,7 @@ export class ResourcesPageComponent implements OnInit {
}
];
- public constructor(private deviceDetectorService: DeviceDetectorService) {
+ public constructor() {
addIcons({ bookOutline, libraryOutline, newspaperOutline, readerOutline });
}
-
- public ngOnInit() {
- this.deviceType = this.deviceDetectorService.getDeviceInfo().deviceType;
- }
}
diff --git a/apps/client/src/app/pages/resources/resources-page.html b/apps/client/src/app/pages/resources/resources-page.html
index bd1338774..5d1bdce9b 100644
--- a/apps/client/src/app/pages/resources/resources-page.html
+++ b/apps/client/src/app/pages/resources/resources-page.html
@@ -1,30 +1 @@
-
-
-
-
-
+
diff --git a/apps/client/src/app/pages/user-account/user-account-page.component.ts b/apps/client/src/app/pages/user-account/user-account-page.component.ts
index 7d5af5423..71b93b2e4 100644
--- a/apps/client/src/app/pages/user-account/user-account-page.component.ts
+++ b/apps/client/src/app/pages/user-account/user-account-page.component.ts
@@ -1,39 +1,30 @@
import { UserService } from '@ghostfolio/client/services/user/user.service';
-import { TabConfiguration, User } from '@ghostfolio/common/interfaces';
+import { User } from '@ghostfolio/common/interfaces';
import { internalRoutes } from '@ghostfolio/common/routes/routes';
-
import {
- ChangeDetectorRef,
- Component,
- CUSTOM_ELEMENTS_SCHEMA,
- DestroyRef,
- OnInit
-} from '@angular/core';
+ GfPageTabsComponent,
+ TabConfiguration
+} from '@ghostfolio/ui/page-tabs';
+
+import { ChangeDetectorRef, Component, DestroyRef } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
-import { MatTabsModule } from '@angular/material/tabs';
-import { RouterModule } from '@angular/router';
-import { IonIcon } from '@ionic/angular/standalone';
import { addIcons } from 'ionicons';
import { diamondOutline, keyOutline, settingsOutline } from 'ionicons/icons';
-import { DeviceDetectorService } from 'ngx-device-detector';
@Component({
host: { class: 'page has-tabs' },
- imports: [IonIcon, MatTabsModule, RouterModule],
- schemas: [CUSTOM_ELEMENTS_SCHEMA],
+ imports: [GfPageTabsComponent],
selector: 'gf-user-account-page',
styleUrls: ['./user-account-page.scss'],
templateUrl: './user-account-page.html'
})
-export class GfUserAccountPageComponent implements OnInit {
- public deviceType: string;
+export class GfUserAccountPageComponent {
public tabs: TabConfiguration[] = [];
public user: User;
public constructor(
private changeDetectorRef: ChangeDetectorRef,
private destroyRef: DestroyRef,
- private deviceDetectorService: DeviceDetectorService,
private userService: UserService
) {
this.userService.stateChanged
@@ -68,8 +59,4 @@ export class GfUserAccountPageComponent implements OnInit {
addIcons({ diamondOutline, keyOutline, settingsOutline });
}
-
- public ngOnInit() {
- this.deviceType = this.deviceDetectorService.getDeviceInfo().deviceType;
- }
}
diff --git a/apps/client/src/app/pages/user-account/user-account-page.html b/apps/client/src/app/pages/user-account/user-account-page.html
index bd1338774..5d1bdce9b 100644
--- a/apps/client/src/app/pages/user-account/user-account-page.html
+++ b/apps/client/src/app/pages/user-account/user-account-page.html
@@ -1,30 +1 @@
-
-
-
-
-
+
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 b3c14b4e0..df3684fd2 100644
--- a/apps/client/src/app/pages/zen/zen-page.component.ts
+++ b/apps/client/src/app/pages/zen/zen-page.component.ts
@@ -1,37 +1,30 @@
import { UserService } from '@ghostfolio/client/services/user/user.service';
-import { TabConfiguration, User } from '@ghostfolio/common/interfaces';
+import { User } from '@ghostfolio/common/interfaces';
import { internalRoutes } from '@ghostfolio/common/routes/routes';
-
import {
- ChangeDetectorRef,
- Component,
- DestroyRef,
- OnInit
-} from '@angular/core';
+ GfPageTabsComponent,
+ TabConfiguration
+} from '@ghostfolio/ui/page-tabs';
+
+import { ChangeDetectorRef, Component, DestroyRef } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
-import { MatTabsModule } from '@angular/material/tabs';
-import { RouterModule } from '@angular/router';
-import { IonIcon } from '@ionic/angular/standalone';
import { addIcons } from 'ionicons';
import { albumsOutline, analyticsOutline } from 'ionicons/icons';
-import { DeviceDetectorService } from 'ngx-device-detector';
@Component({
host: { class: 'page has-tabs' },
- imports: [IonIcon, MatTabsModule, RouterModule],
+ imports: [GfPageTabsComponent],
selector: 'gf-zen-page',
styleUrls: ['./zen-page.scss'],
templateUrl: './zen-page.html'
})
-export class GfZenPageComponent implements OnInit {
- public deviceType: string;
+export class GfZenPageComponent {
public tabs: TabConfiguration[] = [];
public user: User;
public constructor(
private changeDetectorRef: ChangeDetectorRef,
private destroyRef: DestroyRef,
- private deviceDetectorService: DeviceDetectorService,
private userService: UserService
) {
this.userService.stateChanged
@@ -58,8 +51,4 @@ export class GfZenPageComponent implements OnInit {
addIcons({ albumsOutline, analyticsOutline });
}
-
- public ngOnInit() {
- this.deviceType = this.deviceDetectorService.getDeviceInfo().deviceType;
- }
}
diff --git a/apps/client/src/app/pages/zen/zen-page.html b/apps/client/src/app/pages/zen/zen-page.html
index bd1338774..5d1bdce9b 100644
--- a/apps/client/src/app/pages/zen/zen-page.html
+++ b/apps/client/src/app/pages/zen/zen-page.html
@@ -1,30 +1 @@
-
-
-
-
-
+
diff --git a/apps/client/src/styles.scss b/apps/client/src/styles.scss
index 4138d9d9b..83fd69c91 100644
--- a/apps/client/src/styles.scss
+++ b/apps/client/src/styles.scss
@@ -265,16 +265,6 @@ body {
}
}
- .page {
- &.has-tabs {
- @media (min-width: 576px) {
- .mat-mdc-tab-header {
- background-color: rgba(var(--palette-foreground-base-dark), 0.02);
- }
- }
- }
- }
-
.svgMap-tooltip {
background: var(--dark-background);
@@ -489,7 +479,6 @@ ngx-skeleton-loader {
.page {
display: flex;
- flex-direction: column;
overflow-y: auto;
padding-bottom: env(safe-area-inset-bottom);
padding-bottom: constant(safe-area-inset-bottom);
@@ -506,44 +495,6 @@ ngx-skeleton-loader {
padding: 2rem 0;
}
}
-
- &.has-tabs {
- height: calc(100svh - var(--mat-toolbar-standard-height));
-
- .fab-container {
- @media (max-width: 575.98px) {
- bottom: 5rem;
- }
- }
-
- .mat-mdc-tab-nav-panel {
- padding: 2rem 0;
- }
-
- @include mat.tabs-overrides(
- (
- divider-height: 0
- )
- );
-
- @media (min-width: 576px) {
- flex-direction: row-reverse;
-
- .mat-mdc-tab-header {
- background-color: rgba(var(--palette-foreground-base), 0.02);
- padding: 2rem 0;
- width: 14rem;
-
- .mat-mdc-tab-links {
- flex-direction: column;
-
- .mat-mdc-tab-link {
- justify-content: flex-start;
- }
- }
- }
- }
- }
}
.svgMap-tooltip {
diff --git a/apps/client/src/styles/theme.scss b/apps/client/src/styles/theme.scss
index 3cec572cc..f8a194651 100644
--- a/apps/client/src/styles/theme.scss
+++ b/apps/client/src/styles/theme.scss
@@ -293,24 +293,6 @@ $gf-typography: (
container-shape: 4px
)
);
-
- .page.has-tabs {
- @include mat.tabs-overrides(
- (
- container-height: 3rem
- )
- );
- }
- }
-
- @media (min-width: 576px) {
- .page.has-tabs {
- @include mat.tabs-overrides(
- (
- container-height: 2rem
- )
- );
- }
}
@include mat.badge-overrides(
@@ -436,15 +418,6 @@ $gf-typography: (
)
);
}
-
- .page.has-tabs {
- @include mat.tabs-overrides(
- (
- active-indicator-height: 0,
- label-text-tracking: normal
- )
- );
- }
}
:root {
diff --git a/libs/common/src/lib/interfaces/index.ts b/libs/common/src/lib/interfaces/index.ts
index 89874da60..536fc0feb 100644
--- a/libs/common/src/lib/interfaces/index.ts
+++ b/libs/common/src/lib/interfaces/index.ts
@@ -91,7 +91,6 @@ import type { SubscriptionOffer } from './subscription-offer.interface';
import type { SymbolItem } from './symbol-item.interface';
import type { SymbolMetrics } from './symbol-metrics.interface';
import type { SystemMessage } from './system-message.interface';
-import type { TabConfiguration } from './tab-configuration.interface';
import type { ToggleOption } from './toggle-option.interface';
import type { UserItem } from './user-item.interface';
import type { UserSettings } from './user-settings.interface';
@@ -186,7 +185,6 @@ export {
SymbolItem,
SymbolMetrics,
SystemMessage,
- TabConfiguration,
ToggleOption,
User,
UserItem,
diff --git a/libs/ui/src/lib/page-tabs/index.ts b/libs/ui/src/lib/page-tabs/index.ts
new file mode 100644
index 000000000..a7b3468fd
--- /dev/null
+++ b/libs/ui/src/lib/page-tabs/index.ts
@@ -0,0 +1,2 @@
+export * from './interfaces/interfaces';
+export * from './page-tabs.component';
diff --git a/libs/common/src/lib/interfaces/tab-configuration.interface.ts b/libs/ui/src/lib/page-tabs/interfaces/interfaces.ts
similarity index 100%
rename from libs/common/src/lib/interfaces/tab-configuration.interface.ts
rename to libs/ui/src/lib/page-tabs/interfaces/interfaces.ts
diff --git a/libs/ui/src/lib/page-tabs/page-tabs.component.html b/libs/ui/src/lib/page-tabs/page-tabs.component.html
new file mode 100644
index 000000000..fa9af9b11
--- /dev/null
+++ b/libs/ui/src/lib/page-tabs/page-tabs.component.html
@@ -0,0 +1,30 @@
+
+
+
+
+
diff --git a/libs/ui/src/lib/page-tabs/page-tabs.component.scss b/libs/ui/src/lib/page-tabs/page-tabs.component.scss
new file mode 100644
index 000000000..bed3596bb
--- /dev/null
+++ b/libs/ui/src/lib/page-tabs/page-tabs.component.scss
@@ -0,0 +1,70 @@
+@use '@angular/material' as mat;
+
+:host {
+ display: flex;
+ flex-direction: column;
+ height: calc(100svh - var(--mat-toolbar-standard-height));
+ width: 100%;
+
+ @include mat.tabs-overrides(
+ (
+ active-indicator-height: 0,
+ divider-height: 0,
+ label-text-tracking: normal
+ )
+ );
+
+ .fab-container {
+ @media (max-width: 575.98px) {
+ bottom: 5rem;
+ }
+ }
+
+ ::ng-deep {
+ .mat-mdc-tab-nav-panel {
+ padding: 2rem 0;
+ }
+ }
+
+ @media (max-width: 575.98px) {
+ @include mat.tabs-overrides(
+ (
+ container-height: 3rem
+ )
+ );
+ }
+
+ @media (min-width: 576px) {
+ flex-direction: row-reverse;
+
+ @include mat.tabs-overrides(
+ (
+ container-height: 2rem
+ )
+ );
+
+ ::ng-deep {
+ .mat-mdc-tab-header {
+ background-color: rgba(var(--palette-foreground-base), 0.02);
+ padding: 2rem 0;
+ width: 14rem;
+
+ .mat-mdc-tab-links {
+ flex-direction: column;
+
+ .mat-mdc-tab-link {
+ justify-content: flex-start;
+ }
+ }
+ }
+ }
+ }
+}
+
+:host-context(.theme-dark) {
+ @media (min-width: 576px) {
+ .mat-mdc-tab-header {
+ background-color: rgba(var(--palette-foreground-base-dark), 0.02);
+ }
+ }
+}
diff --git a/libs/ui/src/lib/page-tabs/page-tabs.component.ts b/libs/ui/src/lib/page-tabs/page-tabs.component.ts
new file mode 100644
index 000000000..61c2caf05
--- /dev/null
+++ b/libs/ui/src/lib/page-tabs/page-tabs.component.ts
@@ -0,0 +1,30 @@
+import {
+ ChangeDetectionStrategy,
+ Component,
+ inject,
+ input
+} from '@angular/core';
+import { MatTabsModule } from '@angular/material/tabs';
+import { RouterModule } from '@angular/router';
+import { IonIcon } from '@ionic/angular/standalone';
+import { DeviceDetectorService } from 'ngx-device-detector';
+
+import { TabConfiguration } from './interfaces/interfaces';
+
+@Component({
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ imports: [IonIcon, MatTabsModule, RouterModule],
+ selector: 'gf-page-tabs',
+ styleUrls: ['./page-tabs.component.scss'],
+ templateUrl: './page-tabs.component.html'
+})
+export class GfPageTabsComponent {
+ public deviceType: string;
+ public readonly tabs = input.required();
+
+ private readonly deviceService = inject(DeviceDetectorService);
+
+ public constructor() {
+ this.deviceType = this.deviceService.getDeviceInfo().deviceType;
+ }
+}