Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
cf234003ec | |||
8d3954304e | |||
9562139fa6 | |||
c857ea9a8f |
12
CHANGELOG.md
@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 1.200.0 - 01.10.2022
|
||||
|
||||
### Added
|
||||
|
||||
- Added a mini statistics section to the landing page including pulls on _Docker Hub_
|
||||
- Added an _As seen in_ section to the landing page
|
||||
- Added support for an icon in the value component
|
||||
|
||||
### Changed
|
||||
|
||||
- Upgraded `prisma` from version `4.1.1` to `4.4.0`
|
||||
|
||||
## 1.199.1 - 27.09.2022
|
||||
|
||||
### Added
|
||||
|
@ -145,6 +145,27 @@ export class InfoService {
|
||||
});
|
||||
}
|
||||
|
||||
private async countDockerHubPulls(): Promise<number> {
|
||||
try {
|
||||
const get = bent(
|
||||
`https://hub.docker.com/v2/repositories/ghostfolio/ghostfolio`,
|
||||
'GET',
|
||||
'json',
|
||||
200,
|
||||
{
|
||||
'User-Agent': 'request'
|
||||
}
|
||||
);
|
||||
|
||||
const { pull_count } = await get();
|
||||
return pull_count;
|
||||
} catch (error) {
|
||||
Logger.error(error, 'InfoService');
|
||||
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private async countGitHubContributors(): Promise<number> {
|
||||
try {
|
||||
const get = bent(
|
||||
@ -245,6 +266,8 @@ export class InfoService {
|
||||
const activeUsers1d = await this.countActiveUsers(1);
|
||||
const activeUsers30d = await this.countActiveUsers(30);
|
||||
const newUsers30d = await this.countNewUsers(30);
|
||||
|
||||
const dockerHubPulls = await this.countDockerHubPulls();
|
||||
const gitHubContributors = await this.countGitHubContributors();
|
||||
const gitHubStargazers = await this.countGitHubStargazers();
|
||||
const slackCommunityUsers = await this.countSlackCommunityUsers();
|
||||
@ -252,6 +275,7 @@ export class InfoService {
|
||||
statistics = {
|
||||
activeUsers1d,
|
||||
activeUsers30d,
|
||||
dockerHubPulls,
|
||||
gitHubContributors,
|
||||
gitHubStargazers,
|
||||
newUsers30d,
|
||||
|
@ -1,4 +1,7 @@
|
||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { DataService } from '@ghostfolio/client/services/data.service';
|
||||
import { Statistics } from '@ghostfolio/common/interfaces/statistics.interface';
|
||||
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
|
||||
import { format } from 'date-fns';
|
||||
import { Subject } from 'rxjs';
|
||||
|
||||
@ -11,6 +14,8 @@ import { Subject } from 'rxjs';
|
||||
export class LandingPageComponent implements OnDestroy, OnInit {
|
||||
public currentYear = format(new Date(), 'yyyy');
|
||||
public demoAuthToken: string;
|
||||
public hasPermissionForStatistics: boolean;
|
||||
public statistics: Statistics;
|
||||
public testimonials = [
|
||||
{
|
||||
author: 'Philipp',
|
||||
@ -36,7 +41,16 @@ export class LandingPageComponent implements OnDestroy, OnInit {
|
||||
|
||||
private unsubscribeSubject = new Subject<void>();
|
||||
|
||||
public constructor() {}
|
||||
public constructor(private dataService: DataService) {
|
||||
const { globalPermissions, statistics } = this.dataService.fetchInfo();
|
||||
|
||||
this.hasPermissionForStatistics = hasPermission(
|
||||
globalPermissions,
|
||||
permissions.enableStatistics
|
||||
);
|
||||
|
||||
this.statistics = statistics;
|
||||
}
|
||||
|
||||
public ngOnInit() {}
|
||||
|
||||
|
@ -42,6 +42,103 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="hasPermissionForStatistics" class="row mb-5">
|
||||
<div class="col-md-4 d-flex my-1">
|
||||
<a
|
||||
class="d-block"
|
||||
title="Ghostfolio in Numbers: Monthly Active Users (MAU)"
|
||||
[routerLink]="['/about']"
|
||||
>
|
||||
<gf-value
|
||||
icon="people-outline"
|
||||
size="large"
|
||||
[value]="statistics?.activeUsers30d ?? '-'"
|
||||
>Monthly Active Users</gf-value
|
||||
>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-4 d-flex my-1">
|
||||
<a
|
||||
class="d-block"
|
||||
title="Ghostfolio in Numbers: Stars on GitHub"
|
||||
[routerLink]="['/about']"
|
||||
>
|
||||
<gf-value
|
||||
icon="star-outline"
|
||||
size="large"
|
||||
[value]="statistics?.gitHubStargazers ?? '-'"
|
||||
>Stars on GitHub</gf-value
|
||||
>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-4 d-flex my-1">
|
||||
<a
|
||||
class="d-block"
|
||||
title="Ghostfolio in Numbers: Pulls on Docker Hub"
|
||||
[routerLink]="['/about']"
|
||||
>
|
||||
<gf-value
|
||||
icon="cloud-download-outline"
|
||||
size="large"
|
||||
[value]="statistics?.dockerHubPulls ?? '-'"
|
||||
>Pulls on Docker Hub</gf-value
|
||||
>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-5">
|
||||
<div class="col-12 text-center text-muted"><small>As seen in</small></div>
|
||||
<div class="col-md-2 d-flex justify-content-center my-1">
|
||||
<a
|
||||
class="d-block logo logo-alternative-to mask"
|
||||
href="https://alternativeto.net"
|
||||
target="_blank"
|
||||
title="AlternativeTo - Crowdsourced software recommendations"
|
||||
></a>
|
||||
</div>
|
||||
<div class="col-md-2 d-flex justify-content-center my-1">
|
||||
<a
|
||||
class="d-block logo logo-awesome"
|
||||
href="https://github.com/awesome-selfhosted/awesome-selfhosted"
|
||||
target="_blank"
|
||||
title="Awesome-Selfhosted: A list of Free Software network services and web applications which can be hosted on your own servers"
|
||||
></a>
|
||||
</div>
|
||||
<div class="col-md-2 d-flex justify-content-center my-1">
|
||||
<a
|
||||
class="d-block logo logo-openstartup"
|
||||
href="https://openstartup.tm"
|
||||
target="_blank"
|
||||
title="Open Startup: The most complete list of open startups"
|
||||
></a>
|
||||
</div>
|
||||
<div class="col-md-2 d-flex justify-content-center my-1">
|
||||
<a
|
||||
class="d-block logo logo-privacy-tools mask"
|
||||
href="https://www.privacytools.io"
|
||||
target="_blank"
|
||||
title="Privacy Tools: Software Alternatives and Encryption"
|
||||
></a>
|
||||
</div>
|
||||
<div class="col-md-2 d-flex justify-content-center my-1">
|
||||
<a
|
||||
class="d-block logo logo-product-hunt"
|
||||
href="https://www.producthunt.com"
|
||||
target="_blank"
|
||||
title="Product Hunt – The best new products in tech."
|
||||
></a>
|
||||
</div>
|
||||
<div class="col-md-2 d-flex justify-content-center my-1">
|
||||
<a
|
||||
class="d-block logo logo-unraid mask"
|
||||
href="https://unraid.net"
|
||||
target="_blank"
|
||||
title="Unraid | Unleash Your Hardware"
|
||||
></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row my-5">
|
||||
<div class="col text-center">
|
||||
<h2 class="h4 mb-1 text-center">
|
||||
@ -58,20 +155,20 @@
|
||||
<div class="row my-3">
|
||||
<div class="col-md-4 my-2">
|
||||
<mat-card>
|
||||
<mat-card-title class="text-center">360° View</mat-card-title>
|
||||
<mat-card-title>360° View</mat-card-title>
|
||||
Get the full picture of your personal finances across multiple
|
||||
platforms.
|
||||
</mat-card>
|
||||
</div>
|
||||
<div class="col-md-4 my-2">
|
||||
<mat-card>
|
||||
<mat-card-title class="text-center">Web3 Ready</mat-card-title>
|
||||
<mat-card-title>Web3 Ready</mat-card-title>
|
||||
Use Ghostfolio anonymously and own your financial data.
|
||||
</mat-card>
|
||||
</div>
|
||||
<div class="col-md-4 my-2">
|
||||
<mat-card>
|
||||
<mat-card-title class="text-center">Open Source</mat-card-title>
|
||||
<mat-card-title>Open Source</mat-card-title>
|
||||
Benefit from continuous improvements through a strong community.
|
||||
</mat-card>
|
||||
</div>
|
||||
@ -196,7 +293,7 @@
|
||||
</div>
|
||||
|
||||
<div class="row my-5">
|
||||
<div class="col-md-6 offset-md-3">
|
||||
<div class="col">
|
||||
<h2 class="h4 mb-1 text-center">Are <strong>you</strong> ready?</h2>
|
||||
<p class="lead mb-3 text-center">
|
||||
Join now or check out the example account
|
||||
@ -240,7 +337,7 @@
|
||||
<div class="row">
|
||||
<div class="align-items-center d-flex flex-column w-100">
|
||||
<a
|
||||
class="agplv3-logo"
|
||||
class="logo logo-agplv3 mask"
|
||||
href="https://www.gnu.org/licenses/agpl-3.0.html"
|
||||
target="_blank"
|
||||
title="GNU Affero General Public License Version 3"
|
||||
|
@ -4,6 +4,7 @@ import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { GfLogoModule } from '@ghostfolio/ui/logo';
|
||||
import { GfValueModule } from '@ghostfolio/ui/value';
|
||||
|
||||
import { LandingPageRoutingModule } from './landing-page-routing.module';
|
||||
import { LandingPageComponent } from './landing-page.component';
|
||||
@ -13,6 +14,7 @@ import { LandingPageComponent } from './landing-page.component';
|
||||
imports: [
|
||||
CommonModule,
|
||||
GfLogoModule,
|
||||
GfValueModule,
|
||||
LandingPageRoutingModule,
|
||||
MatButtonModule,
|
||||
MatCardModule,
|
||||
|
@ -3,16 +3,6 @@
|
||||
:host {
|
||||
display: block;
|
||||
|
||||
.agplv3-logo {
|
||||
background-color: rgba(var(--dark-primary-text));
|
||||
height: 3rem;
|
||||
mask-image: url('/assets/images/AGPLv3-logo.svg');
|
||||
mask-position: center;
|
||||
mask-repeat: no-repeat;
|
||||
mask-size: contain;
|
||||
width: 7.5rem;
|
||||
}
|
||||
|
||||
.button-container {
|
||||
.mat-stroked-button {
|
||||
background-color: var(--light-background);
|
||||
@ -34,6 +24,58 @@
|
||||
}
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 3rem;
|
||||
width: 7.5rem;
|
||||
|
||||
&.mask {
|
||||
background-color: rgba(var(--dark-secondary-text));
|
||||
mask-position: center;
|
||||
mask-repeat: no-repeat;
|
||||
mask-size: contain;
|
||||
}
|
||||
|
||||
&.logo-agplv3 {
|
||||
mask-image: url('/assets/images/logo-AGPLv3.svg');
|
||||
}
|
||||
|
||||
&.logo-alternative-to {
|
||||
mask-image: url('/assets/images/logo-alternative-to.svg');
|
||||
}
|
||||
|
||||
&.logo-awesome {
|
||||
background-image: url('/assets/images/logo-awesome.png');
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
filter: grayscale(1);
|
||||
}
|
||||
|
||||
&.logo-openstartup {
|
||||
background-image: url('/assets/images/logo-openstartup.png');
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
filter: grayscale(1);
|
||||
}
|
||||
|
||||
&.logo-privacy-tools {
|
||||
mask-image: url('/assets/images/logo-privacy-tools.svg');
|
||||
}
|
||||
|
||||
&.logo-product-hunt {
|
||||
background-image: url('/assets/images/logo-product-hunt.png');
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
filter: grayscale(1);
|
||||
}
|
||||
|
||||
&.logo-unraid {
|
||||
mask-image: url('/assets/images/logo-unraid.svg');
|
||||
}
|
||||
}
|
||||
|
||||
.outro-inner-container {
|
||||
aspect-ratio: 16 / 9;
|
||||
max-height: 66vh;
|
||||
@ -56,16 +98,21 @@
|
||||
}
|
||||
|
||||
:host-context(.is-dark-theme) {
|
||||
.agplv3-logo {
|
||||
background-color: rgba(var(--light-primary-text));
|
||||
}
|
||||
|
||||
.button-container {
|
||||
.mat-stroked-button {
|
||||
background-color: var(--dark-background);
|
||||
}
|
||||
}
|
||||
|
||||
.logo {
|
||||
&.logo-agplv3,
|
||||
&.logo-alternative-to,
|
||||
&.logo-privacy-tools,
|
||||
&.logo-unraid {
|
||||
background-color: rgba(var(--light-primary-text));
|
||||
}
|
||||
}
|
||||
|
||||
.outro-inner-container {
|
||||
div {
|
||||
background-image: url('/assets/intro-dark.jpg') !important;
|
||||
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
1
apps/client/src/assets/images/logo-alternative-to.svg
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
apps/client/src/assets/images/logo-awesome.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
apps/client/src/assets/images/logo-openstartup.png
Normal file
After Width: | Height: | Size: 56 KiB |
35
apps/client/src/assets/images/logo-privacy-tools.svg
Normal file
@ -0,0 +1,35 @@
|
||||
<svg version="1.2" baseProfile="tiny-ps" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 508 101" width="508" height="101">
|
||||
<title>horizontal-svg</title>
|
||||
<style>
|
||||
tspan { white-space:pre }
|
||||
.shp0 { fill: #3498db }
|
||||
.shp1 { fill: transparent }
|
||||
.shp2 { fill: #8a9595 }
|
||||
</style>
|
||||
<g id="Logo">
|
||||
<g id="Shield">
|
||||
<g id="Layer">
|
||||
<path id="Layer" class="shp0" d="M284.81 0C279.86 0.24 254.33 8.51 242.56 14.89C240.87 15.81 239.01 18.96 239 20.34C239 33 242.05 51.67 250.66 68.26L267.5 51.42C264.25 43.19 266.19 33.81 272.44 27.56C276.25 23.94 283.41 21.26 289.64 21.15C292.47 21.1 295.11 21.58 297.15 22.74C298.34 23.43 297.78 24.32 297.42 24.68L284.52 37.05C282.89 38.8 284.3 43.29 285.36 46.15C288.21 47.2 292.7 48.61 294.45 46.98L306.83 34.08C307.18 33.73 308.07 33.17 308.76 34.36C312.47 40.88 309.21 53.53 303.95 59.06C297.69 65.32 288.31 67.26 280.09 64L260.76 83.33C267.04 90.61 274.95 96.69 284.81 100.54C320.46 86.63 330.62 43.46 330.62 20.34C330.61 18.96 328.76 15.81 327.06 14.89C315.29 8.51 289.76 0.24 284.81 0L284.81 0Z" />
|
||||
<g id="Layer">
|
||||
<path id="Layer" class="shp1" d="M250.69 68.23C250.93 68.68 251.17 69.13 251.41 69.58C252.43 71.46 253.52 73.31 254.69 75.12C255.86 76.93 257.1 78.69 258.43 80.4C259.19 81.38 259.98 82.35 260.8 83.3L280.12 63.97C288.35 67.23 297.73 65.29 303.98 59.03C309.25 53.5 312.51 40.85 308.8 34.33C308.11 33.14 307.22 33.7 306.86 34.05L294.49 46.95C292.74 48.58 288.25 47.17 285.39 46.12C284.34 43.26 282.93 38.77 284.56 37.02L297.46 24.65C297.81 24.29 298.37 23.4 297.18 22.71C295.14 21.55 292.51 21.07 289.68 21.12C283.45 21.23 276.28 23.91 272.48 27.53C266.22 33.79 264.28 43.16 267.54 51.39L250.69 68.23Z" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Tools">
|
||||
<path id="Layer" class="shp2" d="M343.3 31.55L343.3 24.61L387.83 24.61L387.83 31.55L369.48 31.55L369.48 76.83L361.65 76.83L361.65 31.55L343.3 31.55Z" />
|
||||
<path id="Layer" fill-rule="evenodd" class="shp2" d="M381.33 50.12C382.38 47.68 383.79 45.59 385.58 43.85C387.37 42.06 389.46 40.67 391.85 39.67C394.29 38.63 396.87 38.11 399.61 38.11C402.34 38.11 404.9 38.63 407.29 39.67C409.73 40.67 411.82 42.06 413.56 43.85C415.35 45.59 416.74 47.68 417.73 50.12C418.78 52.5 419.3 55.06 419.3 57.8C419.3 60.58 418.78 63.2 417.73 65.63C416.74 68.02 415.35 70.11 413.56 71.9C411.82 73.64 409.73 75.03 407.29 76.08C404.9 77.07 402.34 77.57 399.61 77.57C396.87 77.57 394.29 77.07 391.85 76.08C389.46 75.03 387.37 73.64 385.58 71.9C383.79 70.11 382.38 68.02 381.33 65.63C380.34 63.2 379.84 60.58 379.84 57.8C379.84 55.06 380.34 52.5 381.33 50.12ZM408.33 67.2C410.77 64.61 411.99 61.48 411.99 57.8C411.99 54.12 410.77 51.01 408.33 48.48C405.95 45.94 403.04 44.67 399.61 44.67C396.18 44.67 393.24 45.94 390.8 48.48C388.37 51.01 387.15 54.12 387.15 57.8C387.15 61.48 388.34 64.61 390.73 67.2C393.17 69.73 396.13 71 399.61 71C403.04 71 405.95 69.73 408.33 67.2Z" />
|
||||
<path id="Layer" fill-rule="evenodd" class="shp2" d="M423.45 50.12C424.5 47.68 425.91 45.59 427.7 43.85C429.49 42.06 431.58 40.67 433.97 39.67C436.41 38.63 438.99 38.11 441.73 38.11C444.46 38.11 447.02 38.63 449.41 39.67C451.85 40.67 453.94 42.06 455.68 43.85C457.47 45.59 458.86 47.68 459.85 50.12C460.9 52.5 461.42 55.06 461.42 57.8C461.42 60.58 460.9 63.2 459.85 65.63C458.86 68.02 457.47 70.11 455.68 71.9C453.94 73.64 451.85 75.03 449.41 76.08C447.02 77.07 444.46 77.57 441.73 77.57C438.99 77.57 436.41 77.07 433.97 76.08C431.58 75.03 429.49 73.64 427.7 71.9C425.91 70.11 424.5 68.02 423.45 65.63C422.46 63.2 421.96 60.58 421.96 57.8C421.96 55.06 422.46 52.5 423.45 50.12ZM450.45 67.2C452.89 64.61 454.11 61.48 454.11 57.8C454.11 54.12 452.89 51.01 450.45 48.48C448.07 45.94 445.16 44.67 441.73 44.67C438.3 44.67 435.36 45.94 432.92 48.48C430.49 51.01 429.27 54.12 429.27 57.8C429.27 61.48 430.46 64.61 432.85 67.2C435.29 69.73 438.25 71 441.73 71C445.16 71 448.07 69.73 450.45 67.2Z" />
|
||||
<path id="Layer" class="shp2" d="M473.1 22.97L473.1 76.83L465.64 76.83L465.64 24.61L473.1 22.97Z" />
|
||||
<path id="Layer" class="shp2" d="M475.48 71.9L479.51 66.98C481.5 68.52 483.51 69.71 485.55 70.56C487.64 71.35 489.75 71.75 491.89 71.75C494.58 71.75 496.76 71.23 498.45 70.18C500.15 69.14 500.99 67.77 500.99 66.08C500.99 64.74 500.49 63.67 499.5 62.87C498.5 62.08 496.96 61.53 494.87 61.23L488.01 60.26C484.28 59.72 481.45 58.57 479.51 56.83C477.62 55.04 476.67 52.68 476.67 49.75C476.67 46.31 478.04 43.55 480.78 41.47C483.51 39.33 487.09 38.26 491.52 38.26C494.3 38.26 496.94 38.66 499.42 39.45C501.96 40.25 504.42 41.47 506.81 43.11L503 48.03C500.92 46.64 498.88 45.64 496.89 45.05C494.95 44.4 492.98 44.08 490.99 44.08C488.71 44.08 486.87 44.55 485.48 45.49C484.08 46.44 483.39 47.68 483.39 49.22C483.39 50.62 483.86 51.69 484.8 52.43C485.8 53.13 487.41 53.65 489.65 54L496.51 54.97C500.24 55.51 503.08 56.68 505.02 58.47C507.01 60.26 508 62.63 508 65.56C508 67.25 507.58 68.84 506.73 70.33C505.94 71.78 504.82 73.02 503.38 74.06C501.99 75.11 500.32 75.95 498.38 76.6C496.44 77.2 494.35 77.49 492.11 77.49C488.83 77.49 485.75 77.02 482.86 76.08C480.03 75.13 477.57 73.74 475.48 71.9L475.48 71.9Z" />
|
||||
</g>
|
||||
<g id="Privacy">
|
||||
<path id="Layer" fill-rule="evenodd" class="shp2" d="M1.46 76.82L1.46 24.6L25.63 24.6C30.7 24.6 34.8 26.07 37.94 29.01C41.12 31.89 42.71 35.64 42.71 40.27C42.71 44.85 41.12 48.57 37.94 51.46C34.75 54.34 30.65 55.79 25.63 55.79L9.29 55.79L9.29 76.82L1.46 76.82ZM24.81 31.47L9.29 31.47L9.29 49.15L24.81 49.15C27.84 49.15 30.25 48.35 32.04 46.76C33.88 45.12 34.8 42.95 34.8 40.27C34.8 37.58 33.88 35.45 32.04 33.85C30.25 32.26 27.84 31.47 24.81 31.47L24.81 31.47Z" />
|
||||
<path id="Layer" class="shp2" d="M46.91 76.82L46.91 38.85L54.37 38.85L54.37 43.7C55.51 41.86 56.98 40.47 58.77 39.52C60.56 38.53 62.57 38.03 64.81 38.03C65.61 38.03 66.3 38.08 66.9 38.18C67.5 38.28 68.07 38.43 68.62 38.63L68.62 45.34C67.92 45.09 67.2 44.89 66.45 44.74C65.71 44.6 64.96 44.52 64.22 44.52C62.03 44.52 60.06 45.12 58.32 46.31C56.63 47.46 55.31 49.17 54.37 51.46L54.37 76.82L46.91 76.82Z" />
|
||||
<path id="Layer" class="shp2" d="M75.41 32.74C74.17 32.74 73.1 32.29 72.2 31.4C71.31 30.45 70.86 29.36 70.86 28.12C70.86 26.87 71.31 25.8 72.2 24.91C73.1 23.96 74.17 23.49 75.41 23.49C76.65 23.49 77.72 23.96 78.62 24.91C79.56 25.8 80.03 26.87 80.03 28.12C80.03 29.36 79.56 30.45 78.62 31.4C77.72 32.29 76.65 32.74 75.41 32.74L75.41 32.74ZM79.14 38.86L79.14 76.82L71.68 76.82L71.68 38.86L79.14 38.86Z" />
|
||||
<path id="Layer" class="shp2" d="M97.33 76.82L80.92 38.85L89.12 38.85L100.98 67.27L112.84 38.85L120.83 38.85L104.41 76.82L97.33 76.82Z" />
|
||||
<path id="Layer" fill-rule="evenodd" class="shp2" d="M134.56 77.5C130.43 77.5 127.08 76.43 124.49 74.29C121.9 72.15 120.61 69.37 120.61 65.94C120.61 62.36 121.98 59.55 124.71 57.51C127.45 55.42 131.2 54.38 135.98 54.38C137.82 54.38 139.61 54.57 141.35 54.97C143.09 55.32 144.75 55.82 146.35 56.46L146.35 52.44C146.35 49.75 145.55 47.74 143.96 46.39C142.37 45.05 140.08 44.38 137.1 44.38C135.36 44.38 133.54 44.65 131.65 45.2C129.76 45.7 127.65 46.49 125.31 47.59L122.55 41.99C125.39 40.65 128.07 39.68 130.61 39.08C133.14 38.44 135.65 38.11 138.14 38.11C143.06 38.11 146.87 39.31 149.55 41.7C152.29 44.03 153.66 47.36 153.66 51.69L153.66 76.83L146.35 76.83L146.35 73.55C144.66 74.89 142.84 75.88 140.9 76.53C138.96 77.18 136.85 77.5 134.56 77.5L134.56 77.5ZM127.77 65.79C127.77 67.63 128.54 69.12 130.08 70.26C131.68 71.41 133.74 71.98 136.28 71.98C138.26 71.98 140.1 71.68 141.8 71.09C143.49 70.49 145 69.59 146.35 68.4L146.35 61.84C144.9 61.04 143.39 60.47 141.8 60.12C140.2 59.72 138.46 59.52 136.57 59.52C133.89 59.52 131.75 60.09 130.16 61.24C128.57 62.38 127.77 63.9 127.77 65.79L127.77 65.79Z" />
|
||||
<path id="Layer" class="shp2" d="M177.4 70.93C179.29 70.93 181.08 70.56 182.77 69.81C184.46 69.02 186.08 67.85 187.62 66.31L192.09 71.15C190.11 73.14 187.82 74.71 185.23 75.85C182.65 76.95 179.94 77.49 177.1 77.49C174.37 77.49 171.81 77 169.42 76C167.03 74.96 164.97 73.57 163.23 71.83C161.49 70.08 160.09 68.02 159.05 65.63C158.06 63.2 157.56 60.59 157.56 57.8C157.56 55.07 158.06 52.51 159.05 50.12C160.09 47.68 161.49 45.59 163.23 43.85C164.97 42.06 167.03 40.67 169.42 39.68C171.81 38.63 174.37 38.11 177.1 38.11C179.94 38.11 182.7 38.68 185.38 39.82C188.07 40.92 190.4 42.46 192.39 44.45L187.69 49.52C186.25 47.98 184.64 46.81 182.85 46.02C181.06 45.17 179.19 44.75 177.25 44.75C173.82 44.75 170.91 46.02 168.52 48.55C166.14 51.09 164.94 54.17 164.94 57.8C164.94 61.53 166.14 64.66 168.52 67.2C170.96 69.69 173.92 70.93 177.4 70.93L177.4 70.93Z" />
|
||||
<path id="Layer" class="shp2" d="M204.75 80.4L206.24 76.97L191.1 38.85L199.31 38.85L210.42 67.87L222.65 38.85L230.71 38.85L212.36 81.37C210.62 85.4 208.63 88.28 206.39 90.02C204.15 91.81 201.29 92.71 197.81 92.71C197.02 92.71 196.27 92.66 195.57 92.56C194.93 92.51 194.36 92.41 193.86 92.26L193.86 85.7C194.36 85.8 194.85 85.87 195.35 85.92C195.9 85.97 196.52 85.99 197.22 85.99C198.91 85.99 200.37 85.52 201.62 84.58C202.91 83.68 203.95 82.29 204.75 80.4L204.75 80.4Z" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 8.9 KiB |
BIN
apps/client/src/assets/images/logo-product-hunt.png
Normal file
After Width: | Height: | Size: 21 KiB |
9
apps/client/src/assets/images/logo-unraid.svg
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 222.4 139.8">
|
||||
<path fill="#ffffff" d="M146.70000000000002 130.2H135l-3 9h-6.5l13.4-38.5h8l13.4 38.5h-7.1l-10.6-31.6-5.8 16.9h8.2l1.7 5.7zM29.7 100.8v25.4c0 8.9-5.8 13.6-14.9 13.6-9 0-14.8-4.7-14.8-13.6v-25.4h6.5v25.4c0 5.2 3.2 7.9 8.2 7.9 5.2 0 8.4-2.7 8.4-7.9v-25.4h6.6zM50.9 112.7v26.5h-6.5v-38.5h6.1l17 26.5v-26.5H74v38.5h-6.1l-17-26.5zM171.3 100.8h6.5v38.5h-6.5v-38.5zM222.4 125.4c0 9-5.9 13.8-15.2 13.8h-14.5v-38.5h14.6c9.2 0 15.1 4.8 15.1 13.8v10.9zm-6.6-10.8c0-5.3-3.3-8.1-8.5-8.1h-8.1v27.1h8c5.3 0 8.6-2.8 8.6-8.1v-10.9zM108.3 124.7c4.3-1.6 6.9-5.3 6.9-11.5 0-8.7-5.1-12.4-12.8-12.4H88.8v38.5h6.5v-32.8h6.9c3.8 0 6.2 1.8 6.2 6.7s-2.4 6.8-6.2 6.8h-3.4l9.2 19.4h7.5l-7.2-14.7z" class="st0"></path>
|
||||
<linearGradient id="SVGID_1_" x1="68.07" x2="154.073" y1="81.489" y2="-4.514" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#e32929"></stop>
|
||||
<stop offset="1" stop-color="#ff8d30"></stop>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_1_)" d="M107.8 19.2h6.5v38.5h-6.5V19.2zM50.9 57.7h-6.5V19.2h6.5v38.5zm25.2 4.6h6.5V77h-6.5V62.3zM60.2 45.8h6.5v23.8h-6.5V45.8zm31.7 0h6.5v23.8h-6.5V45.8zm79.4-26.6h6.5v38.5h-6.5V19.2zm-25.2-4.5h-6.5V0h6.5v14.7zM162 31.1h-6.5V7.4h6.5v23.7zm-31.8 0h-6.5V7.4h6.5v23.7z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
@ -18,6 +18,7 @@ $mat-css-light-theme-selector: '.is-light-theme';
|
||||
|
||||
:root {
|
||||
--dark-background: rgb(39, 39, 39);
|
||||
--font-family-sans-serif: Roboto, 'Helvetica Neue', sans-serif;
|
||||
--light-background: rgb(255, 255, 255);
|
||||
}
|
||||
|
||||
@ -146,6 +147,10 @@ ngx-skeleton-loader {
|
||||
@include gf-table;
|
||||
}
|
||||
|
||||
.lead {
|
||||
font-weight: unset;
|
||||
}
|
||||
|
||||
.mat-card {
|
||||
&:not([class*='mat-elevation-z']) {
|
||||
border: 1px solid rgba(var(--dark-dividers));
|
||||
|
@ -1,6 +1,7 @@
|
||||
export interface Statistics {
|
||||
activeUsers1d: number;
|
||||
activeUsers30d: number;
|
||||
dockerHubPulls: number;
|
||||
gitHubContributors: number;
|
||||
gitHubStargazers: number;
|
||||
newUsers30d: number;
|
||||
|
@ -1,67 +1,73 @@
|
||||
<ng-template #label><ng-content></ng-content></ng-template>
|
||||
<ng-container *ngIf="value || value === 0 || value === null">
|
||||
<div
|
||||
class="d-flex"
|
||||
[ngClass]="position === 'end' ? 'justify-content-end' : ''"
|
||||
>
|
||||
<ng-container *ngIf="isNumber || value === null">
|
||||
<ng-container *ngIf="colorizeSign && !useAbsoluteValue">
|
||||
<div *ngIf="value > 0" class="mr-1 text-success">+</div>
|
||||
<div *ngIf="value < 0" class="mr-1 text-danger">-</div>
|
||||
<div *ngIf="icon" class="align-self-center mr-3">
|
||||
<ion-icon class="h3 m-0" [name]="icon"></ion-icon>
|
||||
</div>
|
||||
<div>
|
||||
<ng-template #label><ng-content></ng-content></ng-template>
|
||||
<ng-container *ngIf="value || value === 0 || value === null">
|
||||
<div
|
||||
class="d-flex"
|
||||
[ngClass]="position === 'end' ? 'justify-content-end' : ''"
|
||||
>
|
||||
<ng-container *ngIf="isNumber || value === null">
|
||||
<ng-container *ngIf="colorizeSign && !useAbsoluteValue">
|
||||
<div *ngIf="value > 0" class="mr-1 text-success">+</div>
|
||||
<div *ngIf="value < 0" class="mr-1 text-danger">-</div>
|
||||
</ng-container>
|
||||
<div
|
||||
*ngIf="isPercent"
|
||||
class="mb-0 value"
|
||||
[ngClass]="{ h2: size === 'large', h4: size === 'medium' }"
|
||||
>
|
||||
{{ formattedValue }}%
|
||||
</div>
|
||||
<div
|
||||
*ngIf="!isPercent"
|
||||
class="mb-0 value"
|
||||
[ngClass]="{ h2: size === 'large', h4: size === 'medium' }"
|
||||
>
|
||||
<ng-container *ngIf="value === null">
|
||||
<span class="text-monospace text-muted">***</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="value !== null">
|
||||
{{ formattedValue }}
|
||||
</ng-container>
|
||||
</div>
|
||||
<small *ngIf="currency && size === 'medium'" class="ml-1">
|
||||
{{ currency }}
|
||||
</small>
|
||||
<div *ngIf="currency && size !== 'medium'" class="ml-1">
|
||||
{{ currency }}
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="isString">
|
||||
<div
|
||||
class="mb-0 text-truncate value"
|
||||
[ngClass]="{ h2: size === 'large', h4: size === 'medium' }"
|
||||
>
|
||||
{{ formattedValue | titlecase }}
|
||||
</div>
|
||||
</ng-container>
|
||||
<div
|
||||
*ngIf="isPercent"
|
||||
class="mb-0 value"
|
||||
[ngClass]="{ h2: size === 'large', h4: size === 'medium' }"
|
||||
>
|
||||
{{ formattedValue }}%
|
||||
</div>
|
||||
<div
|
||||
*ngIf="!isPercent"
|
||||
class="mb-0 value"
|
||||
[ngClass]="{ h2: size === 'large', h4: size === 'medium' }"
|
||||
>
|
||||
<ng-container *ngIf="value === null">
|
||||
<span class="text-monospace text-muted">***</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="value !== null">
|
||||
{{ formattedValue }}
|
||||
</ng-container>
|
||||
</div>
|
||||
<small *ngIf="currency && size === 'medium'" class="ml-1">
|
||||
{{ currency }}
|
||||
</small>
|
||||
<div *ngIf="currency && size !== 'medium'" class="ml-1">
|
||||
{{ currency }}
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="isString">
|
||||
<div
|
||||
class="mb-0 text-truncate value"
|
||||
[ngClass]="{ h2: size === 'large', h4: size === 'medium' }"
|
||||
>
|
||||
{{ formattedValue | titlecase }}
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
<ng-container>
|
||||
<div *ngIf="size === 'large'">
|
||||
<span class="h6"
|
||||
><ng-container *ngTemplateOutlet="label"></ng-container
|
||||
></span>
|
||||
<span *ngIf="subLabel" class="text-muted"> {{ subLabel }}</span>
|
||||
</div>
|
||||
<small *ngIf="size !== 'large'">
|
||||
<ng-container *ngTemplateOutlet="label"></ng-container>
|
||||
</small>
|
||||
<ng-container>
|
||||
<div *ngIf="size === 'large'">
|
||||
<span class="h6"
|
||||
><ng-container *ngTemplateOutlet="label"></ng-container
|
||||
></span>
|
||||
<span *ngIf="subLabel" class="text-muted"> {{ subLabel }}</span>
|
||||
</div>
|
||||
<small *ngIf="size !== 'large'">
|
||||
<ng-container *ngTemplateOutlet="label"></ng-container>
|
||||
</small>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<ngx-skeleton-loader
|
||||
*ngIf="value === undefined"
|
||||
animation="pulse"
|
||||
[theme]="{
|
||||
height: size === 'large' ? '2.5rem' : size === 'medium' ? '2rem' : '1.5rem',
|
||||
width: '5rem'
|
||||
}"
|
||||
></ngx-skeleton-loader>
|
||||
<ngx-skeleton-loader
|
||||
*ngIf="value === undefined"
|
||||
animation="pulse"
|
||||
[theme]="{
|
||||
height:
|
||||
size === 'large' ? '2.5rem' : size === 'medium' ? '2rem' : '1.5rem',
|
||||
width: '5rem'
|
||||
}"
|
||||
></ngx-skeleton-loader>
|
||||
</div>
|
||||
|
@ -1,6 +1,6 @@
|
||||
:host {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-direction: row;
|
||||
font-variant-numeric: tabular-nums;
|
||||
|
||||
.h2 {
|
||||
|
@ -16,6 +16,7 @@ import { isNumber } from 'lodash';
|
||||
export class ValueComponent implements OnChanges {
|
||||
@Input() colorizeSign = false;
|
||||
@Input() currency = '';
|
||||
@Input() icon = '';
|
||||
@Input() isAbsolute = false;
|
||||
@Input() isCurrency = false;
|
||||
@Input() isDate = false;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
|
||||
|
||||
import { ValueComponent } from './value.component';
|
||||
@ -8,6 +8,6 @@ import { ValueComponent } from './value.component';
|
||||
declarations: [ValueComponent],
|
||||
exports: [ValueComponent],
|
||||
imports: [CommonModule, NgxSkeletonLoaderModule],
|
||||
providers: []
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||
})
|
||||
export class GfValueModule {}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ghostfolio",
|
||||
"version": "1.199.1",
|
||||
"version": "1.200.0",
|
||||
"homepage": "https://ghostfol.io",
|
||||
"license": "AGPL-3.0",
|
||||
"scripts": {
|
||||
@ -81,7 +81,7 @@
|
||||
"@nestjs/schedule": "2.1.0",
|
||||
"@nestjs/serve-static": "3.0.0",
|
||||
"@nrwl/angular": "14.6.4",
|
||||
"@prisma/client": "4.1.1",
|
||||
"@prisma/client": "4.4.0",
|
||||
"@simplewebauthn/browser": "5.2.1",
|
||||
"@simplewebauthn/server": "5.2.1",
|
||||
"@stripe/stripe-js": "1.22.0",
|
||||
@ -119,7 +119,7 @@
|
||||
"passport": "0.6.0",
|
||||
"passport-google-oauth20": "2.0.0",
|
||||
"passport-jwt": "4.0.0",
|
||||
"prisma": "4.1.1",
|
||||
"prisma": "4.4.0",
|
||||
"reflect-metadata": "0.1.13",
|
||||
"rxjs": "7.5.6",
|
||||
"stripe": "8.199.0",
|
||||
|
36
yarn.lock
@ -3839,22 +3839,22 @@
|
||||
schema-utils "^3.0.0"
|
||||
source-map "^0.7.3"
|
||||
|
||||
"@prisma/client@4.1.1":
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/client/-/client-4.1.1.tgz#dcb1118397deb8247fbe39a1f3eee5606648adf8"
|
||||
integrity sha512-2pXuIUYxHv5H9o6QTa1VIsl4yMgsAjKQOitlo8WVTB+vo73rmMJITBPavdGUZSWUc7adMkFzEV3y5rVTUQr77Q==
|
||||
"@prisma/client@4.4.0":
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/client/-/client-4.4.0.tgz#45f59c172dd3621ecc92d7cf9bc765d85e6c7d56"
|
||||
integrity sha512-ciKOP246x1xwr04G9ajHlJ4pkmtu9Q6esVyqVBO0QJihaKQIUvbPjClp17IsRJyxqNpFm4ScbOc/s9DUzKHINQ==
|
||||
dependencies:
|
||||
"@prisma/engines-version" "4.1.0-48.8d8414deb360336e4698a65aa45a1fbaf1ce13d8"
|
||||
"@prisma/engines-version" "4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6"
|
||||
|
||||
"@prisma/engines-version@4.1.0-48.8d8414deb360336e4698a65aa45a1fbaf1ce13d8":
|
||||
version "4.1.0-48.8d8414deb360336e4698a65aa45a1fbaf1ce13d8"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-4.1.0-48.8d8414deb360336e4698a65aa45a1fbaf1ce13d8.tgz#ce00e6377126e491a8b1e0e2039c97e2924bd6d9"
|
||||
integrity sha512-cRRJwpHFGFJZvtHbY3GZjMffNBEjjZk68ztn+S2hDgPCGB4H66IK26roK94GJxBodSehwRJ0wGyebC2GoIH1JQ==
|
||||
"@prisma/engines-version@4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6":
|
||||
version "4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6.tgz#00875863bb30b670a586a5b5794a000f7f3ad976"
|
||||
integrity sha512-P5v/PuEIJLYXZUZBvOLPqoyCW+m6StNqHdiR6te++gYVODpPdLakks5HVx3JaZIY+LwR02juJWFlwpc9Eog/ug==
|
||||
|
||||
"@prisma/engines@4.1.1":
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-4.1.1.tgz#a6a75870618bbd19ff734c51af7dbe9f362c3265"
|
||||
integrity sha512-DCw8L/SS0IXqmj5IW/fMxOXiifnsfjBzDfRhf0j3NFWqvMCh9OtfjmXQZxVgI2mwvJLc/5jzXhkiWT39qS09dA==
|
||||
"@prisma/engines@4.4.0":
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-4.4.0.tgz#6ca7d3ce8eee08dcfa82311b0a02f5ccaac7dc0c"
|
||||
integrity sha512-Fpykccxlt9MHrAs/QpPGpI2nOiRxuLA+LiApgA59ibbf24YICZIMWd3SI2YD+q0IAIso0jCGiHhirAIbxK3RyQ==
|
||||
|
||||
"@rollup/plugin-babel@^5.3.0":
|
||||
version "5.3.1"
|
||||
@ -16763,12 +16763,12 @@ pretty-hrtime@^1.0.3:
|
||||
resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1"
|
||||
integrity sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==
|
||||
|
||||
prisma@4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/prisma/-/prisma-4.1.1.tgz#41c2e19896357f484ef21567165d762908376fca"
|
||||
integrity sha512-yw50J8If2dKP4wYIi695zthsCASQFHiogGvUHHWd3falx/rpsD6Sb1LMLRV9nO3iGG3lozxNJ2PSINxK7xwdpg==
|
||||
prisma@4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/prisma/-/prisma-4.4.0.tgz#0c53324bf6a29474636b3e1964e0d72e0277bf8f"
|
||||
integrity sha512-l/QKLmLcKJQFuc+X02LyICo0NWTUVaNNZ00jKJBqwDyhwMAhboD1FWwYV50rkH4Wls0RviAJSFzkC2ZrfawpfA==
|
||||
dependencies:
|
||||
"@prisma/engines" "4.1.1"
|
||||
"@prisma/engines" "4.4.0"
|
||||
|
||||
prismjs@^1.27.0, prismjs@^1.28.0:
|
||||
version "1.28.0"
|
||||
|