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..5ff2bc74c 100644 --- a/apps/client/src/app/pages/about/about-page.component.ts +++ b/apps/client/src/app/pages/about/about-page.component.ts @@ -2,19 +2,11 @@ import { UserService } from '@ghostfolio/client/services/user/user.service'; import { TabConfiguration, User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { publicRoutes } from '@ghostfolio/common/routes/routes'; +import { GfPageTabsComponent } 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 +16,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 +33,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 +100,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..55790ce74 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,8 @@ import { TabConfiguration } from '@ghostfolio/common/interfaces'; import { internalRoutes } from '@ghostfolio/common/routes/routes'; +import { GfPageTabsComponent } 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 +11,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 +33,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..afe2a7684 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,25 @@ import { TabConfiguration } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { publicRoutes } from '@ghostfolio/common/routes/routes'; +import { GfPageTabsComponent } 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 +48,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..81e456636 100644 --- a/apps/client/src/app/pages/home/home-page.component.ts +++ b/apps/client/src/app/pages/home/home-page.component.ts @@ -3,18 +3,15 @@ import { UserService } from '@ghostfolio/client/services/user/user.service'; import { TabConfiguration, User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { internalRoutes } from '@ghostfolio/common/routes/routes'; +import { GfPageTabsComponent } 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 +20,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 +36,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 +97,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..909610ac9 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,10 @@ import { UserService } from '@ghostfolio/client/services/user/user.service'; import { TabConfiguration, User } from '@ghostfolio/common/interfaces'; import { internalRoutes } from '@ghostfolio/common/routes/routes'; +import { GfPageTabsComponent } from '@ghostfolio/ui/page-tabs'; -import { - ChangeDetectorRef, - Component, - 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 { addIcons } from 'ionicons'; import { analyticsOutline, @@ -19,24 +13,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 +77,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..0e4fa59c6 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,8 @@ import { TabConfiguration } from '@ghostfolio/common/interfaces'; import { publicRoutes } from '@ghostfolio/common/routes/routes'; +import { GfPageTabsComponent } 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 +10,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 +42,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..51f35368b 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,27 @@ import { UserService } from '@ghostfolio/client/services/user/user.service'; import { TabConfiguration, User } from '@ghostfolio/common/interfaces'; import { internalRoutes } from '@ghostfolio/common/routes/routes'; +import { GfPageTabsComponent } from '@ghostfolio/ui/page-tabs'; -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 { 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 +56,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..53223cca6 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,27 @@ import { UserService } from '@ghostfolio/client/services/user/user.service'; import { TabConfiguration, User } from '@ghostfolio/common/interfaces'; import { internalRoutes } from '@ghostfolio/common/routes/routes'; +import { GfPageTabsComponent } from '@ghostfolio/ui/page-tabs'; -import { - ChangeDetectorRef, - Component, - 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 { 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 +48,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..9d782235b 100644 --- a/apps/client/src/styles.scss +++ b/apps/client/src/styles.scss @@ -489,7 +489,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); @@ -508,37 +507,39 @@ ngx-skeleton-loader { } &.has-tabs { - height: calc(100svh - var(--mat-toolbar-standard-height)); + gf-page-tabs { + height: calc(100svh - var(--mat-toolbar-standard-height)); - .fab-container { - @media (max-width: 575.98px) { - bottom: 5rem; + .fab-container { + @media (max-width: 575.98px) { + bottom: 5rem; + } } - } - .mat-mdc-tab-nav-panel { - padding: 2rem 0; - } + .mat-mdc-tab-nav-panel { + padding: 2rem 0; + } - @include mat.tabs-overrides( - ( - divider-height: 0 - ) - ); + @include mat.tabs-overrides( + ( + divider-height: 0 + ) + ); - @media (min-width: 576px) { - flex-direction: row-reverse; + @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-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-links { + flex-direction: column; - .mat-mdc-tab-link { - justify-content: flex-start; + .mat-mdc-tab-link { + justify-content: flex-start; + } } } } 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..76df72f89 --- /dev/null +++ b/libs/ui/src/lib/page-tabs/index.ts @@ -0,0 +1 @@ +export * from './page-tabs.component'; 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..c7bb7d24d --- /dev/null +++ b/libs/ui/src/lib/page-tabs/page-tabs.component.scss @@ -0,0 +1,5 @@ +:host { + display: flex; + flex-direction: column; + width: 100%; +} 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..e2f1059f9 --- /dev/null +++ b/libs/ui/src/lib/page-tabs/page-tabs.component.ts @@ -0,0 +1,23 @@ +import { TabConfiguration } from '@ghostfolio/common/interfaces'; + +import { ChangeDetectionStrategy, Component, 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'; + +@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(); + + public constructor(deviceService: DeviceDetectorService) { + this.deviceType = deviceService.getDeviceInfo().deviceType; + } +}