mirror of https://github.com/ghostfolio/ghostfolio
committed by
GitHub
26 changed files with 679 additions and 351 deletions
@ -1,178 +1,20 @@ |
|||||
<div class="container"> |
<mat-tab-nav-panel #tabPanel class="flex-grow-1 overflow-auto"> |
||||
<div class="mb-5 row"> |
<router-outlet></router-outlet> |
||||
<div class="col"> |
</mat-tab-nav-panel> |
||||
<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"> |
<nav mat-align-tabs="center" mat-tab-nav-bar [tabPanel]="tabPanel"> |
||||
<div *ngIf="hasPermissionForSubscription" class="col-md-3 col-xs-12 my-2"> |
<ng-container *ngFor="let tab of tabs"> |
||||
<a |
<a |
||||
class="py-4 w-100" |
#rla="routerLinkActive" |
||||
color="primary" |
*ngIf="tab.showCondition !== false" |
||||
mat-flat-button |
class="px-3" |
||||
[routerLink]="['/faq']" |
mat-tab-link |
||||
>FAQ</a |
routerLinkActive |
||||
> |
[active]="rla.isActive" |
||||
</div> |
[routerLink]="tab.path" |
||||
<div |
|
||||
class="col-md-3 col-xs-12 my-2" |
|
||||
[ngClass]="{ 'mx-auto': !hasPermissionForBlog }" |
|
||||
> |
> |
||||
<a |
<ion-icon size="large" [name]="tab.iconName"></ion-icon> |
||||
class="py-4 w-100" |
<div class="d-none d-sm-block ml-2">{{ tab.label }}</div> |
||||
color="primary" |
</a> |
||||
mat-flat-button |
</ng-container> |
||||
[routerLink]="['/about', 'changelog']" |
</nav> |
||||
>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> |
|
||||
|
@ -1,13 +1,14 @@ |
|||||
import { CommonModule } from '@angular/common'; |
import { CommonModule } from '@angular/common'; |
||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; |
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 { AboutPageRoutingModule } from './about-page-routing.module'; |
||||
import { AboutPageComponent } from './about-page.component'; |
import { AboutPageComponent } from './about-page.component'; |
||||
|
|
||||
@NgModule({ |
@NgModule({ |
||||
declarations: [AboutPageComponent], |
declarations: [AboutPageComponent], |
||||
imports: [AboutPageRoutingModule, CommonModule, MatButtonModule], |
imports: [CommonModule, MatTabsModule, AboutPageRoutingModule, RouterModule], |
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA] |
schemas: [CUSTOM_ELEMENTS_SCHEMA] |
||||
}) |
}) |
||||
export class AboutPageModule {} |
export class AboutPageModule {} |
||||
|
@ -1,36 +1,35 @@ |
|||||
|
@import 'apps/client/src/styles/ghostfolio-style'; |
||||
|
|
||||
:host { |
:host { |
||||
color: rgb(var(--dark-primary-text)); |
color: rgb(var(--dark-primary-text)); |
||||
display: block; |
display: flex; |
||||
|
flex-direction: column; |
||||
|
height: calc(100vh - 5rem); |
||||
|
overflow-y: auto; |
||||
|
|
||||
.about-container { |
padding-bottom: env(safe-area-inset-bottom); |
||||
a { |
padding-bottom: constant(safe-area-inset-bottom); |
||||
color: rgba(var(--palette-primary-500), 1); |
|
||||
font-weight: 500; |
|
||||
|
|
||||
&:hover { |
::ng-deep { |
||||
color: rgba(var(--palette-primary-300), 1); |
gf-about-page, |
||||
} |
gf-changelog-page, |
||||
|
gf-privacy-policy-page { |
||||
|
flex: 1 1 auto; |
||||
|
overflow-y: auto; |
||||
} |
} |
||||
|
|
||||
.independent-and-bootstrapped-logo { |
.mat-mdc-tab-link-container { |
||||
background-image: url('/assets/bootstrapped-dark.svg'); |
--mdc-tab-indicator-active-indicator-color: transparent; |
||||
background-position: center; |
|
||||
background-repeat: no-repeat; |
.mat-mdc-tab-link { |
||||
background-size: contain; |
&:hover { |
||||
height: 2rem; |
opacity: 0.75; |
||||
opacity: 0.87; |
} |
||||
width: 10rem; |
} |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
|
|
||||
:host-context(.is-dark-theme) { |
:host-context(.is-dark-theme) { |
||||
color: rgb(var(--light-primary-text)); |
color: rgb(var(--light-primary-text)); |
||||
|
|
||||
.about-container { |
|
||||
.independent-and-bootstrapped-logo { |
|
||||
background-image: url('/assets/bootstrapped-light.svg'); |
|
||||
opacity: 1; |
|
||||
} |
|
||||
} |
|
||||
} |
} |
||||
|
@ -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 {} |
@ -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(); |
||||
|
} |
||||
|
} |
@ -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> |
@ -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 {} |
@ -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; |
||||
|
} |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue