Improve sidebar (#2343)

* Improve sidebar

* Improve style of system message

* Update changelog
pull/2346/head
Thomas Kaul 9 months ago committed by GitHub
parent 7f25066f0f
commit 6f6ff94979
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Improved the style of the system message
- Upgraded _Postgres_ from version `12` to `15` in the `docker-compose` files
## 2.1.0 - 2023-09-15

@ -1,37 +1,26 @@
<header>
<gf-header
class="position-fixed w-100"
[currentRoute]="currentRoute"
[info]="info"
[pageTitle]="pageTitle"
[user]="user"
(signOut)="onSignOut()"
></gf-header>
</header>
<main role="main">
<div
*ngIf="canCreateAccount || (info?.systemMessage && user)"
class="container info-message-container"
class="info-message-container"
>
<div class="row">
<div class="col-md-8 offset-md-2 text-center">
<div class="info-message-inner-container position-fixed w-100">
<div class="align-items-center d-flex h-100 justify-content-center">
<a
*ngIf="canCreateAccount"
class="text-center"
[routerLink]="routerLinkRegister"
>
<div
class="cursor-pointer d-inline-block info-message px-3 py-2"
class="cursor-pointer d-inline-block info-message"
(click)="onCreateAccount()"
>
<span>You are using the Live Demo.</span>
<span class="a ml-2">Create Account</span>
<span i18n>You are using the Live Demo.</span>
<span class="a ml-2" i18n>Create Account</span>
</div></a
>
<div
*ngIf="!canCreateAccount && info?.systemMessage && user"
class="cursor-pointer d-inline-block info-message px-3 py-2 text-truncate"
class="cursor-pointer d-inline-block info-message text-truncate"
(click)="onShowSystemMessage()"
>
{{ info.systemMessage }}
@ -40,6 +29,18 @@
</div>
</div>
<gf-header
class="position-fixed w-100"
[currentRoute]="currentRoute"
[hasTabs]="hasTabs"
[info]="info"
[pageTitle]="pageTitle"
[user]="user"
(signOut)="onSignOut()"
></gf-header>
</header>
<main role="main">
<router-outlet></router-outlet>
</main>

@ -4,31 +4,47 @@
display: block;
min-height: 100vh;
&.has-info-message {
header {
height: calc(2 * var(--mat-toolbar-standard-height));
.info-message-container {
height: var(--mat-toolbar-standard-height);
.info-message-inner-container {
background-color: rgba(var(--palette-primary-500), 1);
height: var(--mat-toolbar-standard-height);
z-index: 999;
.info-message {
color: rgba(var(--palette-foreground-text), 1);
font-size: 80%;
max-width: 100%;
.a {
font-weight: 500;
}
}
}
}
}
main {
min-height: calc(100vh - 2 * var(--mat-toolbar-standard-height));
}
}
footer {
background-color: rgba(var(--palette-foreground-text), 0.05);
font-size: 90%;
}
header {
height: var(--mat-toolbar-standard-height);
}
main {
min-height: 100vh;
padding-top: 5rem;
.info-message-container {
height: 3.5rem;
margin-top: -0.5rem;
.info-message {
background-color: rgba(var(--palette-foreground-text), 0.05);
border-radius: 2rem;
font-size: 80%;
max-width: 100%;
.a {
color: rgba(var(--palette-primary-500), 1);
font-weight: 500;
}
}
}
min-height: calc(100vh - var(--mat-toolbar-standard-height));
}
}
@ -36,12 +52,4 @@
footer {
background-color: rgba(var(--palette-foreground-text-dark), 0.05);
}
main {
.info-message-container {
.info-message {
background-color: rgba(var(--palette-foreground-text-dark), 0.05);
}
}
}
}

@ -3,6 +3,7 @@ import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
HostBinding,
Inject,
OnDestroy,
OnInit
@ -28,14 +29,20 @@ import { UserService } from './services/user/user.service';
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnDestroy, OnInit {
@HostBinding('class.has-info-message') get getHasMessage() {
return this.hasInfoMessage;
}
public canCreateAccount: boolean;
public currentRoute: string;
public currentYear = new Date().getFullYear();
public deviceType: string;
public hasInfoMessage: boolean;
public hasPermissionForBlog: boolean;
public hasPermissionForStatistics: boolean;
public hasPermissionForSubscription: boolean;
public hasPermissionToAccessFearAndGreedIndex: boolean;
public hasTabs = false;
public info: InfoItem;
public pageTitle: string;
public routerLinkAbout = ['/' + $localize`about`];
@ -103,6 +110,14 @@ export class AppComponent implements OnDestroy, OnInit {
const urlSegments = urlSegmentGroup.segments;
this.currentRoute = urlSegments[0].path;
this.hasTabs =
(this.currentRoute === this.routerLinkAbout[0].slice(1) ||
this.currentRoute === 'admin' ||
this.currentRoute === 'home' ||
this.currentRoute === 'portfolio' ||
this.currentRoute === 'zen') &&
this.deviceType !== 'mobile';
this.showFooter =
(this.currentRoute === 'blog' ||
this.currentRoute === this.routerLinkFaq[0].slice(1) ||
@ -140,6 +155,12 @@ export class AppComponent implements OnDestroy, OnInit {
permissions.createUserAccount
);
this.hasInfoMessage =
hasPermission(
this.user?.permissions,
permissions.createUserAccount
) || !!this.info.systemMessage;
this.initializeTheme(this.user?.settings.colorScheme);
this.changeDetectorRef.markForCheck();

@ -8,7 +8,6 @@ import { Subject } from 'rxjs';
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'page' },
selector: 'gf-admin-settings',
styleUrls: ['./admin-settings.component.scss'],
templateUrl: './admin-settings.component.html'

@ -1,14 +1,17 @@
<mat-toolbar class="px-2">
<mat-toolbar class="px-0">
<ng-container *ngIf="user">
<a
class="align-items-center d-flex h-100 no-min-width px-2 rounded-0"
mat-button
[routerLink]="['/']"
>
<gf-logo [label]="pageTitle"></gf-logo>
</a>
<div class="d-flex h-100 logo-container" [ngClass]="{ filled: hasTabs }">
<a
class="align-items-center justify-content-start rounded-0"
mat-button
[ngClass]="{ 'w-100': hasTabs }"
[routerLink]="['/']"
>
<gf-logo class="px-2" [label]="pageTitle"></gf-logo>
</a>
</div>
<span class="spacer"></span>
<ul class="alig-items-center d-flex list-inline m-0">
<ul class="alig-items-center d-flex list-inline m-0 px-2">
<li class="list-inline-item">
<a
class="d-none d-sm-block"
@ -246,18 +249,22 @@
</ul>
</ng-container>
<ng-container *ngIf="user === null">
<a
class="align-items-center d-flex h-100 mx-2 no-min-width px-2 rounded-0"
mat-button
[routerLink]="['/']"
>
<gf-logo
[label]="pageTitle"
[showLabel]="currentRoute !== 'register'"
></gf-logo>
</a>
<div class="d-flex h-100 logo-container" [ngClass]="{ filled: hasTabs }">
<a
class="align-items-center justify-content-start rounded-0"
mat-button
[ngClass]="{ 'w-100': hasTabs }"
[routerLink]="['/']"
>
<gf-logo
class="px-2"
[label]="pageTitle"
[showLabel]="currentRoute !== 'register'"
></gf-logo>
</a>
</div>
<span class="spacer"></span>
<ul class="alig-items-center d-flex list-inline m-0">
<ul class="alig-items-center d-flex list-inline m-0 px-2">
<li class="list-inline-item">
<a
class="d-none d-sm-block"

@ -7,6 +7,16 @@
.mat-toolbar {
background-color: var(--light-background);
.logo-container {
&.filled {
background-color: rgba(var(--palette-foreground-base), 0.02);
}
@media (min-width: 576px) {
width: 14rem;
}
}
.list-inline-item {
margin: 0;
}
@ -34,5 +44,11 @@
:host-context(.is-dark-theme) {
.mat-toolbar {
background-color: var(--dark-background);
.logo-container {
&.filled {
background-color: rgba(var(--palette-foreground-base-dark), 0.02);
}
}
}
}

@ -29,6 +29,7 @@ import { catchError, takeUntil } from 'rxjs/operators';
})
export class HeaderComponent implements OnChanges {
@Input() currentRoute: string;
@Input() hasTabs: boolean;
@Input() info: InfoItem;
@Input() pageTitle: string;
@Input() user: User;

@ -1,10 +1,4 @@
import {
ChangeDetectorRef,
Component,
HostBinding,
OnDestroy,
OnInit
} from '@angular/core';
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
import { DataService } from '@ghostfolio/client/services/data.service';
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { TabConfiguration, User } from '@ghostfolio/common/interfaces';
@ -14,18 +8,13 @@ import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({
host: { class: 'page with-tabs' },
host: { class: 'page has-tabs' },
selector: 'gf-about-page',
styleUrls: ['./about-page.scss'],
templateUrl: './about-page.html'
})
export class AboutPageComponent implements OnDestroy, OnInit {
@HostBinding('class.with-info-message') get getHasMessage() {
return this.hasMessage;
}
public deviceType: string;
public hasMessage: boolean;
public hasPermissionForSubscription: boolean;
public tabs: TabConfiguration[] = [];
public user: User;
@ -38,7 +27,7 @@ export class AboutPageComponent implements OnDestroy, OnInit {
private deviceService: DeviceDetectorService,
private userService: UserService
) {
const { globalPermissions, systemMessage } = this.dataService.fetchInfo();
const { globalPermissions } = this.dataService.fetchInfo();
this.hasPermissionForSubscription = hasPermission(
globalPermissions,
@ -75,12 +64,6 @@ export class AboutPageComponent implements OnDestroy, OnInit {
});
this.user = state.user;
this.hasMessage =
hasPermission(
this.user?.permissions,
permissions.createUserAccount
) || !!systemMessage;
this.changeDetectorRef.markForCheck();
}

@ -2,7 +2,12 @@
<router-outlet></router-outlet>
</mat-tab-nav-panel>
<nav mat-align-tabs="center" mat-tab-nav-bar [tabPanel]="tabPanel">
<nav
mat-align-tabs="center"
mat-tab-nav-bar
[disablePagination]="true"
[tabPanel]="tabPanel"
>
<ng-container *ngFor="let tab of tabs">
<a
#rla="routerLinkActive"

@ -2,7 +2,6 @@ import { Component, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs';
@Component({
host: { class: 'page' },
selector: 'gf-changelog-page',
styleUrls: ['./changelog-page.scss'],
templateUrl: './changelog-page.html'

@ -2,7 +2,6 @@ import { Component, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs';
@Component({
host: { class: 'page' },
selector: 'gf-license-page',
styleUrls: ['./license-page.scss'],
templateUrl: './license-page.html'

@ -4,7 +4,6 @@ import { Subject } from 'rxjs';
const ossFriends = require('../../../../assets/oss-friends.json');
@Component({
host: { class: 'page' },
selector: 'gf-oss-friends-page',
styleUrls: ['./oss-friends-page.scss'],
templateUrl: './oss-friends-page.html'

@ -8,7 +8,6 @@ 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'

@ -2,7 +2,6 @@ import { Component, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs';
@Component({
host: { class: 'page' },
selector: 'gf-privacy-policy-page',
styleUrls: ['./privacy-policy-page.scss'],
templateUrl: './privacy-policy-page.html'

@ -1,34 +1,21 @@
import { Component, HostBinding, OnDestroy, OnInit } from '@angular/core';
import { DataService } from '@ghostfolio/client/services/data.service';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { TabConfiguration } from '@ghostfolio/common/interfaces';
import { DeviceDetectorService } from 'ngx-device-detector';
import { Subject } from 'rxjs';
@Component({
host: { class: 'page with-tabs' },
host: { class: 'page has-tabs' },
selector: 'gf-admin-page',
styleUrls: ['./admin-page.scss'],
templateUrl: './admin-page.html'
})
export class AdminPageComponent implements OnDestroy, OnInit {
@HostBinding('class.with-info-message') get getHasMessage() {
return this.hasMessage;
}
public deviceType: string;
public hasMessage: boolean;
public tabs: TabConfiguration[] = [];
private unsubscribeSubject = new Subject<void>();
public constructor(
private dataService: DataService,
private deviceService: DeviceDetectorService
) {
const { systemMessage } = this.dataService.fetchInfo();
this.hasMessage = !!systemMessage;
}
public constructor(private deviceService: DeviceDetectorService) {}
public ngOnInit() {
this.deviceType = this.deviceService.getDeviceInfo().deviceType;

@ -2,7 +2,12 @@
<router-outlet></router-outlet>
</mat-tab-nav-panel>
<nav mat-align-tabs="center" mat-tab-nav-bar [tabPanel]="tabPanel">
<nav
mat-align-tabs="center"
mat-tab-nav-bar
[disablePagination]="true"
[tabPanel]="tabPanel"
>
<ng-container *ngFor="let tab of tabs">
<a
#rla="routerLinkActive"

@ -1,10 +1,4 @@
import {
ChangeDetectorRef,
Component,
HostBinding,
OnDestroy,
OnInit
} from '@angular/core';
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
import { DataService } from '@ghostfolio/client/services/data.service';
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { TabConfiguration, User } from '@ghostfolio/common/interfaces';
@ -14,18 +8,13 @@ import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({
host: { class: 'page with-tabs' },
host: { class: 'page has-tabs' },
selector: 'gf-home-page',
styleUrls: ['./home-page.scss'],
templateUrl: './home-page.html'
})
export class HomePageComponent implements OnDestroy, OnInit {
@HostBinding('class.with-info-message') get getHasMessage() {
return this.hasMessage;
}
public deviceType: string;
public hasMessage: boolean;
public hasPermissionToAccessFearAndGreedIndex: boolean;
public tabs: TabConfiguration[] = [];
public user: User;
@ -38,7 +27,7 @@ export class HomePageComponent implements OnDestroy, OnInit {
private deviceService: DeviceDetectorService,
private userService: UserService
) {
const { globalPermissions, systemMessage } = this.dataService.fetchInfo();
const { globalPermissions } = this.dataService.fetchInfo();
this.hasPermissionToAccessFearAndGreedIndex = hasPermission(
globalPermissions,
@ -74,12 +63,6 @@ export class HomePageComponent implements OnDestroy, OnInit {
];
this.user = state.user;
this.hasMessage =
hasPermission(
this.user?.permissions,
permissions.createUserAccount
) || !!systemMessage;
this.changeDetectorRef.markForCheck();
}
});

@ -2,7 +2,12 @@
<router-outlet></router-outlet>
</mat-tab-nav-panel>
<nav mat-align-tabs="center" mat-tab-nav-bar [tabPanel]="tabPanel">
<nav
mat-align-tabs="center"
mat-tab-nav-bar
[disablePagination]="true"
[tabPanel]="tabPanel"
>
<ng-container *ngFor="let tab of tabs">
<a
#rla="routerLinkActive"

@ -1,7 +1,7 @@
<div class="container">
<div class="row">
<div class="col text-center">
<div class="mt-5">
<div>
<div class="badge badge-light badge-pill border mb-3 px-3 py-2">
<a href="../en/blog/2023/09/ghostfolio-2"
><span class="mr-1 text-uppercase" i18n>New</span>

@ -24,7 +24,6 @@ import { ImportActivitiesDialog } from './import-activities-dialog/import-activi
import { ImportActivitiesDialogParams } from './import-activities-dialog/interfaces/interfaces';
@Component({
host: { class: 'page' },
selector: 'gf-activities-page',
styleUrls: ['./activities-page.scss'],
templateUrl: './activities-page.html'

@ -27,7 +27,6 @@ import { Subject } from 'rxjs';
import { distinctUntilChanged, switchMap, takeUntil } from 'rxjs/operators';
@Component({
host: { class: 'page' },
selector: 'gf-allocations-page',
styleUrls: ['./allocations-page.scss'],
templateUrl: './allocations-page.html'

@ -26,7 +26,6 @@ import { Subject } from 'rxjs';
import { distinctUntilChanged, map, takeUntil } from 'rxjs/operators';
@Component({
host: { class: 'page' },
selector: 'gf-analysis-page',
styleUrls: ['./analysis-page.scss'],
templateUrl: './analysis-page.html'

@ -10,7 +10,6 @@ import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({
host: { class: 'page' },
selector: 'gf-fire-page',
styleUrls: ['./fire-page.scss'],
templateUrl: './fire-page.html'

@ -20,7 +20,6 @@ import { Subject } from 'rxjs';
import { distinctUntilChanged, switchMap, takeUntil } from 'rxjs/operators';
@Component({
host: { class: 'page' },
selector: 'gf-holdings-page',
styleUrls: ['./holdings-page.scss'],
templateUrl: './holdings-page.html'

@ -1,36 +1,18 @@
import {
ChangeDetectorRef,
Component,
HostBinding,
OnDestroy,
OnInit
} from '@angular/core';
import { DataService } from '@ghostfolio/client/services/data.service';
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
import { UserService } from '@ghostfolio/client/services/user/user.service';
import {
InfoItem,
TabConfiguration,
User
} from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { TabConfiguration, User } from '@ghostfolio/common/interfaces';
import { DeviceDetectorService } from 'ngx-device-detector';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({
host: { class: 'page with-tabs' },
host: { class: 'page has-tabs' },
selector: 'gf-portfolio-page',
styleUrls: ['./portfolio-page.scss'],
templateUrl: './portfolio-page.html'
})
export class PortfolioPageComponent implements OnDestroy, OnInit {
@HostBinding('class.with-info-message') get getHasMessage() {
return this.hasMessage;
}
public deviceType: string;
public hasMessage: boolean;
public info: InfoItem;
public tabs: TabConfiguration[] = [];
public user: User;
@ -38,12 +20,9 @@ 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();
this.userService.stateChanged
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((state) => {
@ -77,12 +56,6 @@ export class PortfolioPageComponent implements OnDestroy, OnInit {
];
this.user = state.user;
this.hasMessage =
hasPermission(
this.user?.permissions,
permissions.createUserAccount
) || !!this.info.systemMessage;
this.changeDetectorRef.markForCheck();
}
});

@ -2,7 +2,12 @@
<router-outlet></router-outlet>
</mat-tab-nav-panel>
<nav mat-align-tabs="center" mat-tab-nav-bar [tabPanel]="tabPanel">
<nav
mat-align-tabs="center"
mat-tab-nav-bar
[disablePagination]="true"
[tabPanel]="tabPanel"
>
<ng-container *ngFor="let tab of tabs">
<a
#rla="routerLinkActive"

@ -6,7 +6,7 @@ import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({
host: { class: 'page with-tabs' },
host: { class: 'page has-tabs' },
selector: 'gf-zen-page',
styleUrls: ['./zen-page.scss'],
templateUrl: './zen-page.html'

@ -2,7 +2,12 @@
<router-outlet></router-outlet>
</mat-tab-nav-panel>
<nav mat-align-tabs="center" mat-tab-nav-bar [tabPanel]="tabPanel">
<nav
mat-align-tabs="center"
mat-tab-nav-bar
[disablePagination]="true"
[tabPanel]="tabPanel"
>
<ng-container *ngFor="let tab of tabs">
<a
#rla="routerLinkActive"

@ -275,12 +275,18 @@ body {
}
.page {
&.with-tabs {
&.has-tabs {
.mat-mdc-tab-nav-bar {
--mat-tab-header-inactive-label-text-color: rgba(
var(--light-primary-text)
);
}
@media (min-width: 576px) {
.mat-mdc-tab-header {
background-color: rgba(var(--palette-foreground-base-dark), 0.02);
}
}
}
}
@ -367,6 +373,12 @@ ngx-skeleton-loader {
@include gf-table;
}
.has-info-message {
.page.has-tabs {
height: calc(100vh - 2 * var(--mat-toolbar-standard-height));
}
}
.hidden {
visibility: hidden;
}
@ -469,12 +481,14 @@ ngx-skeleton-loader {
flex-direction: column;
overflow-y: auto;
&:not(.with-tabs) {
padding-bottom: 5rem;
&:not(.has-tabs) {
@media (min-width: 576px) {
padding: 2rem 0;
}
}
&.with-tabs {
height: calc(100vh - 5rem);
&.has-tabs {
height: calc(100vh - var(--mat-toolbar-standard-height));
padding-bottom: env(safe-area-inset-bottom);
padding-bottom: constant(safe-area-inset-bottom);
@ -491,7 +505,10 @@ ngx-skeleton-loader {
flex-direction: row-reverse;
.mat-mdc-tab-header {
width: 12rem;
background-color: rgba(var(--palette-foreground-base), 0.02);
padding: 2rem 0;
width: 14rem;
--mat-tab-header-label-text-tracking: normal;
--mdc-secondary-navigation-tab-container-height: 2rem;
.mat-mdc-tab-links {
@ -502,6 +519,10 @@ ngx-skeleton-loader {
}
}
}
.mat-mdc-tab-nav-panel {
padding: 2rem 0;
}
}
}
}
@ -518,10 +539,6 @@ ngx-skeleton-loader {
text-decoration: underline !important;
}
.with-info-message {
height: calc(100vh - 5rem - 3.5rem + 0.5rem) !important;
}
.with-placeholder-as-option {
.mat-mdc-select-placeholder {
color: rgba(var(--dark-primary-text));

Loading…
Cancel
Save