Browse Source

Add tabs to about page

pull/2030/head
Thomas 2 years ago
parent
commit
1d3c32d3ea
  1. 24
      apps/client/src/app/pages/about/about-page-routing.module.ts
  2. 61
      apps/client/src/app/pages/about/about-page.component.ts
  3. 195
      apps/client/src/app/pages/about/about-page.html
  4. 5
      apps/client/src/app/pages/about/about-page.module.ts
  5. 45
      apps/client/src/app/pages/about/about-page.scss
  6. 20
      apps/client/src/app/pages/about/overview/about-overview-page-routing.module.ts
  7. 61
      apps/client/src/app/pages/about/overview/about-overview-page.component.ts
  8. 157
      apps/client/src/app/pages/about/overview/about-overview-page.html
  9. 13
      apps/client/src/app/pages/about/overview/about-overview-page.module.ts
  10. 36
      apps/client/src/app/pages/about/overview/about-overview-page.scss
  11. 25
      apps/client/src/app/pages/admin/admin-page.html
  12. 24
      apps/client/src/app/pages/home/home-page.html
  13. 25
      apps/client/src/app/pages/portfolio/portfolio-page.html
  14. 24
      apps/client/src/app/pages/zen/zen-page.html

24
apps/client/src/app/pages/about/about-page-routing.module.ts

@ -7,6 +7,30 @@ import { AboutPageComponent } from './about-page.component';
const routes: Routes = [
{
canActivate: [AuthGuard],
children: [
{ path: '', redirectTo: 'overview', pathMatch: 'full' },
{
path: 'overview',
loadChildren: () =>
import('./overview/about-overview-page.module').then(
(m) => m.AboutOverviewPageModule
)
},
{
path: 'changelog',
loadChildren: () =>
import('./changelog/changelog-page.module').then(
(m) => m.ChangelogPageModule
)
},
{
path: 'privacy-policy',
loadChildren: () =>
import('./privacy-policy/privacy-policy-page.module').then(
(m) => m.PrivacyPolicyPageModule
)
}
],
component: AboutPageComponent,
path: '',
title: $localize`About`

61
apps/client/src/app/pages/about/about-page.component.ts

@ -1,26 +1,36 @@
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
import { environment } from '@ghostfolio/client/../environments/environment';
import {
ChangeDetectorRef,
Component,
HostBinding,
OnDestroy,
OnInit
} from '@angular/core';
import { DataService } from '@ghostfolio/client/services/data.service';
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { DEFAULT_LANGUAGE_CODE } from '@ghostfolio/common/config';
import { User } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({
host: { class: 'page' },
selector: 'gf-about-page',
styleUrls: ['./about-page.scss'],
templateUrl: './about-page.html'
})
export class AboutPageComponent implements OnDestroy, OnInit {
public defaultLanguageCode = DEFAULT_LANGUAGE_CODE;
public hasPermissionForBlog: boolean;
@HostBinding('class.with-info-message') get getHasMessage() {
return this.hasMessage;
}
public hasMessage: boolean;
public hasPermissionForSubscription: boolean;
public isLoggedIn: boolean;
public tabs: {
iconName: string;
label: string;
path: string;
showCondition?: boolean;
}[] = [];
public user: User;
public version = environment.version;
private unsubscribeSubject = new Subject<void>();
@ -29,31 +39,50 @@ export class AboutPageComponent implements OnDestroy, OnInit {
private dataService: DataService,
private userService: UserService
) {
const { globalPermissions } = this.dataService.fetchInfo();
this.hasPermissionForBlog = hasPermission(
globalPermissions,
permissions.enableBlog
);
const { globalPermissions, systemMessage } = this.dataService.fetchInfo();
this.hasPermissionForSubscription = hasPermission(
globalPermissions,
permissions.enableSubscription
);
}
public ngOnInit() {
this.userService.stateChanged
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((state) => {
if (state?.user) {
this.tabs = [
{
iconName: 'reader-outline',
label: $localize`About`,
path: 'overview'
},
{
iconName: 'sparkles-outline',
label: $localize`Changelog & License`,
path: 'changelog'
},
{
iconName: 'shield-checkmark-outline',
label: $localize`Privacy Policy`,
path: 'privacy-policy',
showCondition: this.hasPermissionForSubscription
}
];
this.user = state.user;
this.hasMessage =
hasPermission(
this.user?.permissions,
permissions.createUserAccount
) || !!systemMessage;
this.changeDetectorRef.markForCheck();
}
});
}
public ngOnInit() {}
public ngOnDestroy() {
this.unsubscribeSubject.next();
this.unsubscribeSubject.complete();

195
apps/client/src/app/pages/about/about-page.html

@ -1,178 +1,21 @@
<div class="container">
<div class="mb-5 row">
<div class="col">
<h3 class="d-none d-sm-block mb-3 text-center">About Ghostfolio</h3>
<div class="about-container">
<p>
Ghostfolio is a lightweight wealth management application for
individuals to keep track of stocks, ETFs or cryptocurrencies and make
solid, data-driven investment decisions. The source code is fully
available as
<a
href="https://github.com/ghostfolio/ghostfolio"
title="Find Ghostfolio on GitHub"
>open source software</a
>
(OSS) under the
<a
href="https://www.gnu.org/licenses/agpl-3.0.html"
title="GNU Affero General Public License"
>AGPL-3.0 license</a
>
and we share aggregated
<a
href="https://ghostfol.io/{{ defaultLanguageCode }}/open"
title="Open Startup"
>key metrics</a
>
of the platform’s performance. The project has been initiated by
<a href="https://dotsilver.ch" title="Website of Thomas Kaul"
>Thomas Kaul</a
>
and is driven by the efforts of its
<a
href="https://github.com/ghostfolio/ghostfolio/graphs/contributors"
title="Contributors to Ghostfolio"
>contributors</a
>.
<ng-container *ngIf="version">
This instance is running Ghostfolio {{ version }}.
</ng-container>
<ng-container *ngIf="hasPermissionForSubscription"
>Check the system status at
<a href="https://status.ghostfol.io" title="Ghostfolio Status"
>status.ghostfol.io</a
>.</ng-container
>
</p>
<p>
If you encounter a bug or would like to suggest an improvement or a
new
<a [routerLink]="['/features']">feature</a>, please join the
Ghostfolio
<a
href="https://ghostfolio.slack.com"
title="Join the Ghostfolio Slack community"
>Slack community</a
>, tweet to
<a
href="https://twitter.com/ghostfolio_"
title="Tweet to Ghostfolio on Twitter"
>@ghostfolio_</a
><ng-container *ngIf="user?.subscription?.type === 'Premium'"
>, send an e-mail to
<a href="mailto:hi@ghostfol.io" title="Send an e-mail"
>hi@ghostfol.io</a
></ng-container
>
or start a discussion at
<a
href="https://github.com/ghostfolio/ghostfolio"
title="Find Ghostfolio on GitHub"
>GitHub</a
>.
</p>
<p class="text-center">
<a
class="mx-2"
href="https://twitter.com/ghostfolio_"
mat-icon-button
title="Follow Ghostfolio on Twitter"
>
<ion-icon name="logo-twitter"></ion-icon>
</a>
<a
*ngIf="user?.subscription?.type === 'Premium'"
class="mx-2"
href="mailto:hi@ghostfol.io"
mat-icon-button
title="Send an e-mail"
>
<ion-icon name="mail"></ion-icon>
</a>
<a
class="mx-2"
href="https://ghostfolio.slack.com"
mat-icon-button
title="Join the Ghostfolio Slack channel"
>
<ion-icon name="logo-slack"></ion-icon>
</a>
<a
class="mx-2"
href="https://github.com/ghostfolio/ghostfolio"
mat-icon-button
title="Find Ghostfolio on GitHub"
>
<ion-icon name="logo-github"></ion-icon>
</a>
</p>
<div
*ngIf="hasPermissionForSubscription"
class="d-flex justify-content-center"
>
<div
class="independent-and-bootstrapped-logo mb-2"
title="Ghostfolio is an independent & bootstrapped business"
></div>
</div>
<div
*ngIf="!hasPermissionForSubscription"
class="d-flex justify-content-center"
>
<a
href="https://www.buymeacoffee.com/ghostfolio"
target="_blank"
title="Support Ghostfolio"
><img
class="mb-2"
src="../assets/images/button-buy-me-a-coffee.png"
width="180"
/></a>
</div>
</div>
</div>
</div>
<mat-tab-nav-panel #tabPanel class="flex-grow-1 overflow-auto">
<router-outlet></router-outlet>
</mat-tab-nav-panel>
<div class="row">
<div *ngIf="hasPermissionForSubscription" class="col-md-3 col-xs-12 my-2">
<a
class="py-4 w-100"
color="primary"
mat-flat-button
[routerLink]="['/faq']"
>FAQ</a
>
</div>
<div
class="col-md-3 col-xs-12 my-2"
[ngClass]="{ 'mx-auto': !hasPermissionForBlog }"
<nav mat-align-tabs="center" mat-tab-nav-bar [tabPanel]="tabPanel">
<ng-container *ngFor="let tab of tabs">
<a
#rla="routerLinkActive"
*ngIf="tab.showCondition !== false"
class="px-3"
mat-tab-link
routerLinkActive
[active]="rla.isActive"
[hidden]="tab.hidden"
[routerLink]="tab.path"
>
<a
class="py-4 w-100"
color="primary"
mat-flat-button
[routerLink]="['/about', 'changelog']"
>Changelog & License</a
>
</div>
<div *ngIf="hasPermissionForSubscription" class="col-md-3 col-xs-12 my-2">
<a
class="py-4 w-100"
color="primary"
mat-flat-button
[routerLink]="['/about', 'privacy-policy']"
>Privacy Policy</a
>
</div>
<div *ngIf="hasPermissionForBlog" class="col-md-3 col-xs-12 my-2">
<a
class="py-4 w-100"
color="primary"
mat-flat-button
[routerLink]="['/blog']"
>Blog</a
>
</div>
</div>
</div>
<ion-icon size="large" [name]="tab.iconName"></ion-icon>
<div class="d-none d-sm-block ml-2">{{ tab.label }}</div>
</a>
</ng-container>
</nav>

5
apps/client/src/app/pages/about/about-page.module.ts

@ -1,13 +1,14 @@
import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatTabsModule } from '@angular/material/tabs';
import { RouterModule } from '@angular/router';
import { AboutPageRoutingModule } from './about-page-routing.module';
import { AboutPageComponent } from './about-page.component';
@NgModule({
declarations: [AboutPageComponent],
imports: [AboutPageRoutingModule, CommonModule, MatButtonModule],
imports: [CommonModule, MatTabsModule, AboutPageRoutingModule, RouterModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class AboutPageModule {}

45
apps/client/src/app/pages/about/about-page.scss

@ -1,36 +1,35 @@
@import 'apps/client/src/styles/ghostfolio-style';
:host {
color: rgb(var(--dark-primary-text));
display: block;
display: flex;
flex-direction: column;
height: calc(100vh - 5rem);
overflow-y: auto;
.about-container {
a {
color: rgba(var(--palette-primary-500), 1);
font-weight: 500;
padding-bottom: env(safe-area-inset-bottom);
padding-bottom: constant(safe-area-inset-bottom);
&:hover {
color: rgba(var(--palette-primary-300), 1);
}
::ng-deep {
gf-about-page,
gf-changelog-page,
gf-privacy-policy-page {
flex: 1 1 auto;
overflow-y: auto;
}
.independent-and-bootstrapped-logo {
background-image: url('/assets/bootstrapped-dark.svg');
background-position: center;
background-repeat: no-repeat;
background-size: contain;
height: 2rem;
opacity: 0.87;
width: 10rem;
.mat-mdc-tab-link-container {
--mdc-tab-indicator-active-indicator-color: transparent;
.mat-mdc-tab-link {
&:hover {
opacity: 0.75;
}
}
}
}
}
:host-context(.is-dark-theme) {
color: rgb(var(--light-primary-text));
.about-container {
.independent-and-bootstrapped-logo {
background-image: url('/assets/bootstrapped-light.svg');
opacity: 1;
}
}
}

20
apps/client/src/app/pages/about/overview/about-overview-page-routing.module.ts

@ -0,0 +1,20 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AuthGuard } from '@ghostfolio/client/core/auth.guard';
import { AboutOverviewPageComponent } from './about-overview-page.component';
const routes: Routes = [
{
canActivate: [AuthGuard],
component: AboutOverviewPageComponent,
path: '',
title: $localize`About`
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class AboutOverviewPageRoutingModule {}

61
apps/client/src/app/pages/about/overview/about-overview-page.component.ts

@ -0,0 +1,61 @@
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
import { environment } from '@ghostfolio/client/../environments/environment';
import { DataService } from '@ghostfolio/client/services/data.service';
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { DEFAULT_LANGUAGE_CODE } from '@ghostfolio/common/config';
import { User } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({
host: { class: 'page' },
selector: 'gf-about-overview-page',
styleUrls: ['./about-overview-page.scss'],
templateUrl: './about-overview-page.html'
})
export class AboutOverviewPageComponent implements OnDestroy, OnInit {
public defaultLanguageCode = DEFAULT_LANGUAGE_CODE;
public hasPermissionForBlog: boolean;
public hasPermissionForSubscription: boolean;
public isLoggedIn: boolean;
public user: User;
public version = environment.version;
private unsubscribeSubject = new Subject<void>();
public constructor(
private changeDetectorRef: ChangeDetectorRef,
private dataService: DataService,
private userService: UserService
) {
const { globalPermissions } = this.dataService.fetchInfo();
this.hasPermissionForBlog = hasPermission(
globalPermissions,
permissions.enableBlog
);
this.hasPermissionForSubscription = hasPermission(
globalPermissions,
permissions.enableSubscription
);
}
public ngOnInit() {
this.userService.stateChanged
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((state) => {
if (state?.user) {
this.user = state.user;
this.changeDetectorRef.markForCheck();
}
});
}
public ngOnDestroy() {
this.unsubscribeSubject.next();
this.unsubscribeSubject.complete();
}
}

157
apps/client/src/app/pages/about/overview/about-overview-page.html

@ -0,0 +1,157 @@
<div class="container">
<div class="mb-5 row">
<div class="col">
<h3 class="d-none d-sm-block mb-3 text-center">About Ghostfolio</h3>
<div class="about-container">
<p>
Ghostfolio is a lightweight wealth management application for
individuals to keep track of stocks, ETFs or cryptocurrencies and make
solid, data-driven investment decisions. The source code is fully
available as
<a
href="https://github.com/ghostfolio/ghostfolio"
title="Find Ghostfolio on GitHub"
>open source software</a
>
(OSS) under the
<a
href="https://www.gnu.org/licenses/agpl-3.0.html"
title="GNU Affero General Public License"
>AGPL-3.0 license</a
>
and we share aggregated
<a
href="https://ghostfol.io/{{ defaultLanguageCode }}/open"
title="Open Startup"
>key metrics</a
>
of the platform’s performance. The project has been initiated by
<a href="https://dotsilver.ch" title="Website of Thomas Kaul"
>Thomas Kaul</a
>
and is driven by the efforts of its
<a
href="https://github.com/ghostfolio/ghostfolio/graphs/contributors"
title="Contributors to Ghostfolio"
>contributors</a
>.
<ng-container *ngIf="version">
This instance is running Ghostfolio {{ version }}.
</ng-container>
<ng-container *ngIf="hasPermissionForSubscription"
>Check the system status at
<a href="https://status.ghostfol.io" title="Ghostfolio Status"
>status.ghostfol.io</a
>.</ng-container
>
</p>
<p>
If you encounter a bug or would like to suggest an improvement or a
new
<a [routerLink]="['/features']">feature</a>, please join the
Ghostfolio
<a
href="https://ghostfolio.slack.com"
title="Join the Ghostfolio Slack community"
>Slack community</a
>, tweet to
<a
href="https://twitter.com/ghostfolio_"
title="Tweet to Ghostfolio on Twitter"
>@ghostfolio_</a
><ng-container *ngIf="user?.subscription?.type === 'Premium'"
>, send an e-mail to
<a href="mailto:hi@ghostfol.io" title="Send an e-mail"
>hi@ghostfol.io</a
></ng-container
>
or start a discussion at
<a
href="https://github.com/ghostfolio/ghostfolio"
title="Find Ghostfolio on GitHub"
>GitHub</a
>.
</p>
<p class="text-center">
<a
class="mx-2"
href="https://twitter.com/ghostfolio_"
mat-icon-button
title="Follow Ghostfolio on Twitter"
>
<ion-icon name="logo-twitter"></ion-icon>
</a>
<a
*ngIf="user?.subscription?.type === 'Premium'"
class="mx-2"
href="mailto:hi@ghostfol.io"
mat-icon-button
title="Send an e-mail"
>
<ion-icon name="mail"></ion-icon>
</a>
<a
class="mx-2"
href="https://ghostfolio.slack.com"
mat-icon-button
title="Join the Ghostfolio Slack channel"
>
<ion-icon name="logo-slack"></ion-icon>
</a>
<a
class="mx-2"
href="https://github.com/ghostfolio/ghostfolio"
mat-icon-button
title="Find Ghostfolio on GitHub"
>
<ion-icon name="logo-github"></ion-icon>
</a>
</p>
<div
*ngIf="hasPermissionForSubscription"
class="d-flex justify-content-center"
>
<div
class="independent-and-bootstrapped-logo mb-2"
title="Ghostfolio is an independent & bootstrapped business"
></div>
</div>
<div
*ngIf="!hasPermissionForSubscription"
class="d-flex justify-content-center"
>
<a
href="https://www.buymeacoffee.com/ghostfolio"
target="_blank"
title="Support Ghostfolio"
><img
class="mb-2"
src="../assets/images/button-buy-me-a-coffee.png"
width="180"
/></a>
</div>
</div>
</div>
</div>
<div class="row">
<div *ngIf="hasPermissionForSubscription" class="col-md-6 col-xs-12 my-2">
<a
class="py-4 w-100"
color="primary"
mat-flat-button
[routerLink]="['/faq']"
>Frequently Asked Questions (FAQ)</a
>
</div>
<div *ngIf="hasPermissionForBlog" class="col-md-6 col-xs-12 my-2">
<a
class="py-4 w-100"
color="primary"
mat-flat-button
[routerLink]="['/blog']"
>Blog</a
>
</div>
</div>
</div>

13
apps/client/src/app/pages/about/overview/about-overview-page.module.ts

@ -0,0 +1,13 @@
import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { AboutOverviewPageRoutingModule } from './about-overview-page-routing.module';
import { AboutOverviewPageComponent } from './about-overview-page.component';
@NgModule({
declarations: [AboutOverviewPageComponent],
imports: [AboutOverviewPageRoutingModule, CommonModule, MatButtonModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class AboutOverviewPageModule {}

36
apps/client/src/app/pages/about/overview/about-overview-page.scss

@ -0,0 +1,36 @@
:host {
color: rgb(var(--dark-primary-text));
display: block;
.about-container {
a {
color: rgba(var(--palette-primary-500), 1);
font-weight: 500;
&:hover {
color: rgba(var(--palette-primary-300), 1);
}
}
.independent-and-bootstrapped-logo {
background-image: url('/assets/bootstrapped-dark.svg');
background-position: center;
background-repeat: no-repeat;
background-size: contain;
height: 2rem;
opacity: 0.87;
width: 10rem;
}
}
}
:host-context(.is-dark-theme) {
color: rgb(var(--light-primary-text));
.about-container {
.independent-and-bootstrapped-logo {
background-image: url('/assets/bootstrapped-light.svg');
opacity: 1;
}
}
}

25
apps/client/src/app/pages/admin/admin-page.html

@ -3,16 +3,17 @@
</mat-tab-nav-panel>
<nav mat-align-tabs="center" mat-tab-nav-bar [tabPanel]="tabPanel">
<a
#rla="routerLinkActive"
*ngFor="let tab of tabs"
class="px-3"
mat-tab-link
routerLinkActive
[active]="rla.isActive"
[routerLink]="tab.path"
>
<ion-icon size="large" [name]="tab.iconName"></ion-icon>
<div class="d-none d-sm-block ml-2">{{ tab.label }}</div>
</a>
<ng-container *ngFor="let tab of tabs">
<a
#rla="routerLinkActive"
class="px-3"
mat-tab-link
routerLinkActive
[active]="rla.isActive"
[routerLink]="tab.path"
>
<ion-icon size="large" [name]="tab.iconName"></ion-icon>
<div class="d-none d-sm-block ml-2">{{ tab.label }}</div>
</a>
</ng-container>
</nav>

24
apps/client/src/app/pages/home/home-page.html

@ -3,15 +3,17 @@
</mat-tab-nav-panel>
<nav mat-align-tabs="center" mat-tab-nav-bar [tabPanel]="tabPanel">
<a
#rla="routerLinkActive"
*ngFor="let tab of tabs"
mat-tab-link
routerLinkActive
[active]="rla.isActive"
[routerLink]="tab.path"
>
<ion-icon size="large" [name]="tab.iconName"></ion-icon>
<div class="d-none d-sm-block ml-2">{{ tab.label }}</div>
</a>
<ng-container *ngFor="let tab of tabs">
<a
#rla="routerLinkActive"
class="px-3"
mat-tab-link
routerLinkActive
[active]="rla.isActive"
[routerLink]="tab.path"
>
<ion-icon size="large" [name]="tab.iconName"></ion-icon>
<div class="d-none d-sm-block ml-2">{{ tab.label }}</div>
</a>
</ng-container>
</nav>

25
apps/client/src/app/pages/portfolio/portfolio-page.html

@ -3,16 +3,17 @@
</mat-tab-nav-panel>
<nav mat-align-tabs="center" mat-tab-nav-bar [tabPanel]="tabPanel">
<a
#rla="routerLinkActive"
*ngFor="let tab of tabs"
class="px-3"
mat-tab-link
routerLinkActive
[active]="rla.isActive"
[routerLink]="tab.path"
>
<ion-icon size="large" [name]="tab.iconName"></ion-icon>
<div class="d-none d-sm-block ml-2">{{ tab.label }}</div>
</a>
<ng-container *ngFor="let tab of tabs">
<a
#rla="routerLinkActive"
class="px-3"
mat-tab-link
routerLinkActive
[active]="rla.isActive"
[routerLink]="tab.path"
>
<ion-icon size="large" [name]="tab.iconName"></ion-icon>
<div class="d-none d-sm-block ml-2">{{ tab.label }}</div>
</a>
</ng-container>
</nav>

24
apps/client/src/app/pages/zen/zen-page.html

@ -3,15 +3,17 @@
</mat-tab-nav-panel>
<nav mat-align-tabs="center" mat-tab-nav-bar [tabPanel]="tabPanel">
<a
#rla="routerLinkActive"
*ngFor="let tab of tabs"
mat-tab-link
routerLinkActive
[active]="rla.isActive"
[routerLink]="tab.path"
>
<ion-icon size="large" [name]="tab.iconName"></ion-icon>
<div class="d-none d-sm-block ml-2">{{ tab.label }}</div>
</a>
<ng-container *ngFor="let tab of tabs">
<a
#rla="routerLinkActive"
class="px-3"
mat-tab-link
routerLinkActive
[active]="rla.isActive"
[routerLink]="tab.path"
>
<ion-icon size="large" [name]="tab.iconName"></ion-icon>
<div class="d-none d-sm-block ml-2">{{ tab.label }}</div>
</a>
</ng-container>
</nav>

Loading…
Cancel
Save