diff --git a/.vscode/settings.json b/.vscode/settings.json
index 9bf4d12b5..ba68f1b50 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,4 +1,5 @@
{
"editor.defaultFormatter": "esbenp.prettier-vscode",
- "editor.formatOnSave": true
+ "editor.formatOnSave": true,
+ "vsicons.presets.angular": true
}
diff --git a/apps/client/src/app/pages/resources/glossary/resources-glossary-routing.module.ts b/apps/client/src/app/pages/resources/glossary/resources-glossary-routing.module.ts
new file mode 100644
index 000000000..fee6f0064
--- /dev/null
+++ b/apps/client/src/app/pages/resources/glossary/resources-glossary-routing.module.ts
@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+
+import { ResourcesGlossaryPageComponent } from './resources-glossary.component';
+
+const routes: Routes = [
+ {
+ path: '',
+ component: ResourcesGlossaryPageComponent
+ }
+];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule]
+})
+export class ResourcesGlossaryRoutingModule {}
diff --git a/apps/client/src/app/pages/resources/glossary/resources-glossary.component.html b/apps/client/src/app/pages/resources/glossary/resources-glossary.component.html
new file mode 100644
index 000000000..7225a4e69
--- /dev/null
+++ b/apps/client/src/app/pages/resources/glossary/resources-glossary.component.html
@@ -0,0 +1,16 @@
+
+
+
+
Glossary
+
+ @for (item of glossaryItems; track item) {
+
+ }
+
+
+
+
diff --git a/apps/client/src/app/pages/resources/glossary/resources-glossary.component.scss b/apps/client/src/app/pages/resources/glossary/resources-glossary.component.scss
new file mode 100644
index 000000000..e2d265315
--- /dev/null
+++ b/apps/client/src/app/pages/resources/glossary/resources-glossary.component.scss
@@ -0,0 +1,47 @@
+:host {
+ display: block;
+ padding: 1rem;
+}
+
+// Target the parent panel
+:host-context(.mat-tab-nav-panel) {
+ -ms-overflow-style: none; /* IE and Edge */
+ scrollbar-width: none; /* Firefox */
+
+ &::-webkit-scrollbar {
+ /* Chrome, Safari and Opera */
+ display: none;
+ }
+}
+
+.container {
+ max-width: 800px;
+ margin: 0 auto;
+}
+
+h1 {
+ margin-bottom: 2rem;
+}
+
+.glossary-list {
+ .mb-4 {
+ margin-bottom: 2rem;
+ }
+
+ h3 {
+ margin-bottom: 0.5rem;
+ }
+
+ p {
+ margin-bottom: 0.5rem;
+ }
+
+ a {
+ color: #007bff;
+ text-decoration: none;
+
+ &:hover {
+ text-decoration: underline;
+ }
+ }
+}
diff --git a/apps/client/src/app/pages/resources/glossary/resources-glossary.component.ts b/apps/client/src/app/pages/resources/glossary/resources-glossary.component.ts
new file mode 100644
index 000000000..4360c3b23
--- /dev/null
+++ b/apps/client/src/app/pages/resources/glossary/resources-glossary.component.ts
@@ -0,0 +1,53 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'gf-resources-glossary',
+ templateUrl: './resources-glossary.component.html',
+ styleUrls: ['./resources-glossary.component.scss']
+})
+export class ResourcesGlossaryPageComponent {
+ public glossaryItems = [
+ {
+ term: 'Buy and Hold',
+ definition:
+ 'Buy and hold is a passive investment strategy where you buy assets and hold them for a long period regardless of fluctuations in the market.',
+ link: 'https://www.investopedia.com/terms/b/buyandhold.asp'
+ },
+ {
+ term: 'Deflation',
+ definition:
+ 'Deflation is a decrease of the general price level for goods and services in an economy over a period of time.',
+ link: 'https://www.investopedia.com/terms/d/deflation.asp'
+ },
+ {
+ term: 'Dollar-Cost Averaging (DCA)',
+ definition:
+ 'Dollar-cost averaging is an investment strategy where you split the total amount to be invested across periodic purchases of a target asset to reduce the impact of volatility on the overall purchase.',
+ link: 'https://www.investopedia.com/terms/d/dollarcostaveraging.asp'
+ },
+ {
+ term: 'Financial Independence',
+ definition:
+ 'Financial independence is the status of having enough income, for example with a passive income like dividends, to cover your living expenses for the rest of your life.',
+ link: 'https://en.wikipedia.org/wiki/Financial_independence'
+ },
+ {
+ term: 'FIRE',
+ definition:
+ 'FIRE is a movement that promotes saving and investing to achieve financial independence and early retirement.',
+ link: '../en/blog/2023/07/exploring-the-path-to-fire'
+ },
+ {
+ term: 'Inflation',
+ definition:
+ 'Inflation is an increase of the general price level for goods and services in an economy over a period of time.',
+ link: 'https://www.investopedia.com/terms/i/inflation.asp'
+ },
+ {
+ term: 'Stagflation',
+ definition:
+ 'Stagflation describes a situation in which there is a stagnant economy with high unemployment and high inflation.',
+ link: 'https://www.investopedia.com/terms/s/stagflation.asp'
+ }
+ ];
+}
diff --git a/apps/client/src/app/pages/resources/glossary/resources-glossary.module.ts b/apps/client/src/app/pages/resources/glossary/resources-glossary.module.ts
new file mode 100644
index 000000000..1c19fbc5f
--- /dev/null
+++ b/apps/client/src/app/pages/resources/glossary/resources-glossary.module.ts
@@ -0,0 +1,11 @@
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+
+import { ResourcesGlossaryRoutingModule } from './resources-glossary-routing.module';
+import { ResourcesGlossaryPageComponent } from './resources-glossary.component';
+
+@NgModule({
+ declarations: [ResourcesGlossaryPageComponent],
+ imports: [CommonModule, ResourcesGlossaryRoutingModule]
+})
+export class ResourcesGlossaryPageModule {}
diff --git a/apps/client/src/app/pages/resources/guides/resources-guides-routing.module.ts b/apps/client/src/app/pages/resources/guides/resources-guides-routing.module.ts
new file mode 100644
index 000000000..da53f2956
--- /dev/null
+++ b/apps/client/src/app/pages/resources/guides/resources-guides-routing.module.ts
@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+
+import { ResourcesGuidesComponent } from './resources-guides.component';
+
+const routes: Routes = [
+ {
+ path: '',
+ component: ResourcesGuidesComponent
+ }
+];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule]
+})
+export class ResourcesGuidesRoutingModule {}
diff --git a/apps/client/src/app/pages/resources/guides/resources-guides.component.html b/apps/client/src/app/pages/resources/guides/resources-guides.component.html
new file mode 100644
index 000000000..d130ae668
--- /dev/null
+++ b/apps/client/src/app/pages/resources/guides/resources-guides.component.html
@@ -0,0 +1,16 @@
+
+
+
+
Guides
+
+ @for (guide of guides; track guide) {
+
+
{{ guide.title }}
+
{{ guide.description }}
+
Read more →
+
+ }
+
+
+
+
diff --git a/apps/client/src/app/pages/resources/guides/resources-guides.component.scss b/apps/client/src/app/pages/resources/guides/resources-guides.component.scss
new file mode 100644
index 000000000..4e9a621c1
--- /dev/null
+++ b/apps/client/src/app/pages/resources/guides/resources-guides.component.scss
@@ -0,0 +1,43 @@
+:host {
+ display: block;
+ color: rgb(var(--dark-primary-text));
+
+ .container {
+ max-width: 800px;
+ margin: 0 auto;
+ }
+
+ h1 {
+ margin-bottom: 2rem;
+ }
+
+ .guides-list {
+ .mb-4 {
+ margin-bottom: 2rem;
+ }
+
+ h3 {
+ margin-top: 0;
+ margin-bottom: 0.5rem;
+ }
+
+ p {
+ margin-bottom: 0.5rem;
+ }
+
+ a {
+ color: rgba(var(--palette-primary-500), 1);
+ font-weight: 500;
+ text-decoration: none;
+
+ &:hover {
+ color: rgba(var(--palette-primary-300), 1);
+ text-decoration: underline;
+ }
+ }
+ }
+}
+
+:host-context(.theme-dark) {
+ color: rgb(var(--light-primary-text));
+}
diff --git a/apps/client/src/app/pages/resources/guides/resources-guides.component.ts b/apps/client/src/app/pages/resources/guides/resources-guides.component.ts
new file mode 100644
index 000000000..06852b2fb
--- /dev/null
+++ b/apps/client/src/app/pages/resources/guides/resources-guides.component.ts
@@ -0,0 +1,23 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'gf-resources-guides',
+ templateUrl: './resources-guides.component.html',
+ styleUrls: ['./resources-guides.component.scss']
+})
+export class ResourcesGuidesComponent {
+ public guides = [
+ {
+ title: 'Boringly Getting Rich',
+ description:
+ 'The Boringly Getting Rich guide supports you to get started with investing. It introduces a strategy utilizing a broadly diversified, low-cost portfolio excluding the risks of individual stocks.',
+ link: 'https://herget.me/investing-guide'
+ },
+ {
+ title: 'How do I get my finances in order?',
+ description:
+ 'Before you can think of long-term investing, you have to get your finances in order. Learn how you can reach your financial goals easier and faster in this guide.',
+ link: '../en/blog/2022/07/how-do-i-get-my-finances-in-order'
+ }
+ ];
+}
diff --git a/apps/client/src/app/pages/resources/guides/resources-guides.module.ts b/apps/client/src/app/pages/resources/guides/resources-guides.module.ts
new file mode 100644
index 000000000..fcfcb3625
--- /dev/null
+++ b/apps/client/src/app/pages/resources/guides/resources-guides.module.ts
@@ -0,0 +1,11 @@
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+
+import { ResourcesGuidesRoutingModule } from './resources-guides-routing.module';
+import { ResourcesGuidesComponent } from './resources-guides.component';
+
+@NgModule({
+ declarations: [ResourcesGuidesComponent],
+ imports: [CommonModule, ResourcesGuidesRoutingModule]
+})
+export class ResourcesGuidesModule {}
diff --git a/apps/client/src/app/pages/resources/markets/resources-markets-routing.module.ts b/apps/client/src/app/pages/resources/markets/resources-markets-routing.module.ts
new file mode 100644
index 000000000..5dd9d0ff8
--- /dev/null
+++ b/apps/client/src/app/pages/resources/markets/resources-markets-routing.module.ts
@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+
+import { ResourcesMarketsComponent } from './resources-markets.component';
+
+const routes: Routes = [
+ {
+ path: '',
+ component: ResourcesMarketsComponent
+ }
+];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule]
+})
+export class ResourcesMarketsRoutingModule {}
diff --git a/apps/client/src/app/pages/resources/markets/resources-markets.component.html b/apps/client/src/app/pages/resources/markets/resources-markets.component.html
new file mode 100644
index 000000000..e6aae43c2
--- /dev/null
+++ b/apps/client/src/app/pages/resources/markets/resources-markets.component.html
@@ -0,0 +1,16 @@
+
+
+
+
Markets
+
+ @for (resource of marketResources; track resource) {
+
+ }
+
+
+
+
diff --git a/apps/client/src/app/pages/resources/markets/resources-markets.component.scss b/apps/client/src/app/pages/resources/markets/resources-markets.component.scss
new file mode 100644
index 000000000..f02ff31be
--- /dev/null
+++ b/apps/client/src/app/pages/resources/markets/resources-markets.component.scss
@@ -0,0 +1,54 @@
+:host {
+ color: rgb(var(--dark-primary-text));
+ display: block;
+
+ .market-resources {
+ display: grid;
+ gap: 1rem;
+ grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
+
+ .mat-mdc-card {
+ height: 100%;
+ transition: border-color 0.3s ease;
+
+ &:hover {
+ border-color: var(--gf-theme-primary-500);
+ }
+
+ .mat-mdc-card-header {
+ .mat-mdc-card-title {
+ font-size: 1.1rem;
+ }
+ }
+
+ .mat-mdc-card-content {
+ font-size: 0.9rem;
+ }
+
+ .mat-mdc-card-actions {
+ padding: 0 1rem 1rem;
+ }
+
+ a {
+ color: rgba(var(--palette-primary-500), 1);
+ font-weight: 500;
+ text-decoration: none;
+
+ &:hover {
+ color: rgba(var(--palette-primary-300), 1);
+ text-decoration: underline;
+ }
+ }
+ }
+ }
+}
+
+:host-context(.theme-dark) {
+ color: rgb(var(--light-primary-text));
+
+ .market-resources {
+ .mat-mdc-card {
+ background-color: rgba(var(--palette-background-card-dark), 1);
+ }
+ }
+}
diff --git a/apps/client/src/app/pages/resources/markets/resources-markets.component.ts b/apps/client/src/app/pages/resources/markets/resources-markets.component.ts
new file mode 100644
index 000000000..32585d496
--- /dev/null
+++ b/apps/client/src/app/pages/resources/markets/resources-markets.component.ts
@@ -0,0 +1,35 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'gf-resources-markets',
+ templateUrl: './resources-markets.component.html',
+ styleUrls: ['./resources-markets.component.scss']
+})
+export class ResourcesMarketsComponent {
+ public marketResources = [
+ {
+ title: 'Crypto Coins Heatmap',
+ description:
+ 'With the Crypto Coins Heatmap you can track the daily market movements of cryptocurrencies as a visual snapshot.',
+ link: 'https://www.tradingview.com/heatmap/crypto'
+ },
+ {
+ title: 'Fear & Greed Index',
+ description:
+ 'The fear and greed index was developed by CNNMoney to measure the primary emotions (fear and greed) that influence how much investors are willing to pay for stocks.',
+ link: 'https://money.cnn.com/data/fear-and-greed/'
+ },
+ {
+ title: 'Inflation Chart',
+ description:
+ 'Inflation Chart helps you find the intrinsic value of stock markets, stock prices, goods and services by adjusting them to the amount of the money supply (M0, M1, M2) or price of other goods (food or oil).',
+ link: 'https://inflationchart.com'
+ },
+ {
+ title: 'Stock Heatmap',
+ description:
+ 'With the Stock Heatmap you can track the daily market movements of stocks as a visual snapshot.',
+ link: 'https://www.tradingview.com/heatmap/stock'
+ }
+ ];
+}
diff --git a/apps/client/src/app/pages/resources/markets/resources-markets.module.ts b/apps/client/src/app/pages/resources/markets/resources-markets.module.ts
new file mode 100644
index 000000000..3ec93bb3b
--- /dev/null
+++ b/apps/client/src/app/pages/resources/markets/resources-markets.module.ts
@@ -0,0 +1,11 @@
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+
+import { ResourcesMarketsRoutingModule } from './resources-markets-routing.module';
+import { ResourcesMarketsComponent } from './resources-markets.component';
+
+@NgModule({
+ declarations: [ResourcesMarketsComponent],
+ imports: [CommonModule, ResourcesMarketsRoutingModule]
+})
+export class ResourcesMarketsModule {}
diff --git a/apps/client/src/app/pages/resources/overview/resources-overview-routing.module.ts b/apps/client/src/app/pages/resources/overview/resources-overview-routing.module.ts
new file mode 100644
index 000000000..e546c5412
--- /dev/null
+++ b/apps/client/src/app/pages/resources/overview/resources-overview-routing.module.ts
@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+
+import { ResourcesOverviewComponent } from './resources-overview.component';
+
+const routes: Routes = [
+ {
+ path: '',
+ component: ResourcesOverviewComponent
+ }
+];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule]
+})
+export class ResourcesOverviewRoutingModule {}
diff --git a/apps/client/src/app/pages/resources/overview/resources-overview.component.html b/apps/client/src/app/pages/resources/overview/resources-overview.component.html
new file mode 100644
index 000000000..3a3cfb915
--- /dev/null
+++ b/apps/client/src/app/pages/resources/overview/resources-overview.component.html
@@ -0,0 +1,16 @@
+
+
+
+
Resources Overview
+
+ @for (item of overviewItems; track item) {
+
+
{{ item.title }}
+
{{ item.description }}
+
Explore →
+
+ }
+
+
+
+
diff --git a/apps/client/src/app/pages/resources/overview/resources-overview.component.scss b/apps/client/src/app/pages/resources/overview/resources-overview.component.scss
new file mode 100644
index 000000000..8ff4cc7a0
--- /dev/null
+++ b/apps/client/src/app/pages/resources/overview/resources-overview.component.scss
@@ -0,0 +1,43 @@
+:host {
+ display: block;
+ color: rgb(var(--dark-primary-text));
+}
+
+.container {
+ max-width: 800px;
+ margin: 0 auto;
+}
+
+h1 {
+ margin-bottom: 2rem;
+}
+
+.overview-list {
+ .mb-4 {
+ margin-bottom: 2rem;
+ }
+
+ h3 {
+ margin-top: 0;
+ margin-bottom: 0.5rem;
+ }
+
+ p {
+ margin-bottom: 0.5rem;
+ }
+
+ a {
+ color: rgba(var(--palette-primary-500), 1);
+ font-weight: 500;
+ text-decoration: none;
+
+ &:hover {
+ color: rgba(var(--palette-primary-300), 1);
+ text-decoration: underline;
+ }
+ }
+}
+
+:host-context(.theme-dark) {
+ color: rgb(var(--light-primary-text));
+}
diff --git a/apps/client/src/app/pages/resources/overview/resources-overview.component.ts b/apps/client/src/app/pages/resources/overview/resources-overview.component.ts
new file mode 100644
index 000000000..f790d2fe9
--- /dev/null
+++ b/apps/client/src/app/pages/resources/overview/resources-overview.component.ts
@@ -0,0 +1,35 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'gf-resources-overview',
+ templateUrl: './resources-overview.component.html',
+ styleUrls: ['./resources-overview.component.scss']
+})
+export class ResourcesOverviewComponent {
+ public overviewItems = [
+ {
+ title: 'Frequently Asked Questions (FAQ)',
+ description:
+ 'Find quick answers to commonly asked questions about Ghostfolio in our Frequently Asked Questions (FAQ) section.',
+ link: '/faq'
+ },
+ {
+ title: 'Guides',
+ description:
+ 'Explore our guides to help you get started with investing and managing your finances.',
+ link: '/resources/guides'
+ },
+ {
+ title: 'Markets',
+ description:
+ 'Access various market resources and tools to stay informed about financial markets.',
+ link: '/resources/markets'
+ },
+ {
+ title: 'Glossary',
+ description:
+ 'Learn key financial terms and concepts in our comprehensive glossary.',
+ link: '/resources/glossary'
+ }
+ ];
+}
diff --git a/apps/client/src/app/pages/resources/overview/resources-overview.module.ts b/apps/client/src/app/pages/resources/overview/resources-overview.module.ts
new file mode 100644
index 000000000..6cac8ced4
--- /dev/null
+++ b/apps/client/src/app/pages/resources/overview/resources-overview.module.ts
@@ -0,0 +1,12 @@
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+
+import { ResourcesOverviewRoutingModule } from './resources-overview-routing.module';
+import { ResourcesOverviewComponent } from './resources-overview.component';
+
+@NgModule({
+ declarations: [ResourcesOverviewComponent],
+ imports: [CommonModule, RouterModule, ResourcesOverviewRoutingModule]
+})
+export class ResourcesOverviewModule {}
diff --git a/apps/client/src/app/pages/resources/resources-page-routing.module.ts b/apps/client/src/app/pages/resources/resources-page-routing.module.ts
index be2eaa24e..e8edfeaa1 100644
--- a/apps/client/src/app/pages/resources/resources-page-routing.module.ts
+++ b/apps/client/src/app/pages/resources/resources-page-routing.module.ts
@@ -3,22 +3,48 @@ import { AuthGuard } from '@ghostfolio/client/core/auth.guard';
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
+// import { ResourcesGlossaryPageComponent } from './glossary/resources-glossary.component';
+// import { ResourcesGuidesComponent } from './guides/resources-guides.component';
+// import { ResourcesMarketsComponent } from './markets/resources-markets.component';
+// import { ResourcesOverviewComponent } from './overview/resources-overview.component';
import { ResourcesPageComponent } from './resources-page.component';
const routes: Routes = [
{
- canActivate: [AuthGuard],
- component: ResourcesPageComponent,
path: '',
- title: $localize`Resources`
- },
- ...['personal-finance-tools'].map((path) => ({
- path,
- loadChildren: () =>
- import(
- './personal-finance-tools/personal-finance-tools-page.module'
- ).then((m) => m.PersonalFinanceToolsPageModule)
- }))
+ component: ResourcesPageComponent,
+ canActivate: [AuthGuard],
+ children: [
+ {
+ path: 'guides',
+ loadChildren: () =>
+ import('./guides/resources-guides.module').then(
+ (m) => m.ResourcesGuidesModule
+ )
+ },
+ {
+ path: 'markets',
+ loadChildren: () =>
+ import('./markets/resources-markets.module').then(
+ (m) => m.ResourcesMarketsModule
+ )
+ },
+ {
+ path: 'glossary',
+ loadChildren: () =>
+ import('./glossary/resources-glossary.module').then(
+ (m) => m.ResourcesGlossaryPageModule
+ )
+ },
+ {
+ path: '',
+ loadChildren: () =>
+ import('./overview/resources-overview.module').then(
+ (m) => m.ResourcesOverviewModule
+ )
+ }
+ ]
+ }
];
@NgModule({
diff --git a/apps/client/src/app/pages/resources/resources-page.component.ts b/apps/client/src/app/pages/resources/resources-page.component.ts
index 51172c0de..298064632 100644
--- a/apps/client/src/app/pages/resources/resources-page.component.ts
+++ b/apps/client/src/app/pages/resources/resources-page.component.ts
@@ -6,10 +6,10 @@ import { Component, OnInit } from '@angular/core';
import { Subject } from 'rxjs';
@Component({
- host: { class: 'page' },
+ host: { class: 'page has-tabs' },
selector: 'gf-resources-page',
- styleUrls: ['./resources-page.scss'],
- templateUrl: './resources-page.html'
+ templateUrl: './resources-page.html',
+ styleUrls: ['./resources-page.scss']
})
export class ResourcesPageComponent implements OnInit {
public hasPermissionForSubscription: boolean;
@@ -19,6 +19,20 @@ export class ResourcesPageComponent implements OnInit {
'/' + $localize`:snake-case:resources`,
'personal-finance-tools'
];
+ public tabs = [
+ {
+ path: '.',
+ label: $localize`Overview`,
+ iconName: 'information-circle-outline'
+ },
+ { path: 'guides', label: $localize`Guides`, iconName: 'book-outline' },
+ {
+ path: 'markets',
+ label: $localize`Markets`,
+ iconName: 'trending-up-outline'
+ },
+ { path: 'glossary', label: $localize`Glossary`, iconName: 'list-outline' }
+ ];
private unsubscribeSubject = new Subject();
diff --git a/apps/client/src/app/pages/resources/resources-page.html b/apps/client/src/app/pages/resources/resources-page.html
index 49c3d1523..a9dbee450 100644
--- a/apps/client/src/app/pages/resources/resources-page.html
+++ b/apps/client/src/app/pages/resources/resources-page.html
@@ -1,258 +1,30 @@
-
-
-
-
Resources
-
Ghostfolio
-
-
Guides
-
-
Markets
-
-
Glossary
-
-
-
-
-
-
-
- @if (hasPermissionForSubscription) {
-
- }
-
-
-
-
-
+
+
+
+
+
+ @for (tab of tabs; track tab) {
+ @if (tab.showCondition !== false) {
+
+
+ {{ tab.label }}
+
+ }
+ }
+
diff --git a/apps/client/src/app/pages/resources/resources-page.module.ts b/apps/client/src/app/pages/resources/resources-page.module.ts
index 10845a517..c324d1bca 100644
--- a/apps/client/src/app/pages/resources/resources-page.module.ts
+++ b/apps/client/src/app/pages/resources/resources-page.module.ts
@@ -1,12 +1,19 @@
import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
+import { MatTabsModule } from '@angular/material/tabs';
+import { RouterModule } from '@angular/router';
import { ResourcesPageRoutingModule } from './resources-page-routing.module';
import { ResourcesPageComponent } from './resources-page.component';
@NgModule({
declarations: [ResourcesPageComponent],
- imports: [CommonModule, ResourcesPageRoutingModule],
+ imports: [
+ CommonModule,
+ ResourcesPageRoutingModule,
+ MatTabsModule,
+ RouterModule
+ ],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class ResourcesPageModule {}
diff --git a/apps/client/src/app/pages/resources/resources-page.scss b/apps/client/src/app/pages/resources/resources-page.scss
index c3109fdf7..7a197412b 100644
--- a/apps/client/src/app/pages/resources/resources-page.scss
+++ b/apps/client/src/app/pages/resources/resources-page.scss
@@ -1,6 +1,13 @@
:host {
color: rgb(var(--dark-primary-text));
- display: block;
+ display: flex;
+ flex-direction: row;
+ height: 100%;
+
+ // Add this to ensure proper ordering
+ nav {
+ order: 1; // This will force the nav to be first
+ }
a {
color: rgba(var(--palette-primary-500), 1);
@@ -15,3 +22,56 @@
:host-context(.theme-dark) {
color: rgb(var(--light-primary-text));
}
+
+.mat-tab-nav-bar {
+ border-top: none;
+ border-right: 1px solid rgba(0, 0, 0, 0.12);
+ flex-direction: column;
+ width: 240px;
+}
+
+.mat-tab-link {
+ flex-direction: row;
+ justify-content: flex-start;
+ height: 48px;
+ padding: 0 16px;
+ min-width: auto;
+
+ ion-icon {
+ font-size: 24px;
+ }
+
+ .d-none {
+ margin-left: 8px;
+ }
+}
+
+@media (max-width: 599px) {
+ :host {
+ flex-direction: column-reverse;
+ }
+
+ .mat-tab-nav-bar {
+ width: 100%;
+ border-right: none;
+ border-top: 1px solid rgba(0, 0, 0, 0.12);
+ }
+
+ .mat-tab-link {
+ flex-direction: column;
+ height: auto;
+ padding: 8px 16px;
+
+ ion-icon {
+ font-size: 28px;
+ }
+ }
+}
+
+.flex-grow-1 {
+ flex-grow: 1;
+}
+
+.overflow-auto {
+ overflow: auto;
+}
diff --git a/package-lock.json b/package-lock.json
index 492600202..35eb282d7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -29,6 +29,7 @@
"@dfinity/principal": "0.15.7",
"@dinero.js/currencies": "2.0.0-alpha.8",
"@internationalized/number": "3.5.2",
+ "@ionic/angular": "^8.3.2",
"@nestjs/bull": "10.0.1",
"@nestjs/cache-manager": "2.2.2",
"@nestjs/common": "10.1.3",
@@ -4261,6 +4262,36 @@
"@swc/helpers": "^0.5.0"
}
},
+ "node_modules/@ionic/angular": {
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/@ionic/angular/-/angular-8.3.2.tgz",
+ "integrity": "sha512-mbQgWWOzOHdzYEuixJNl2HJ+QUPAakvaG2D/oh7E+gvmA732ppnpHWF8XR35bpIfQJeBby6/mNZN0Bp9RWAkWw==",
+ "license": "MIT",
+ "dependencies": {
+ "@ionic/core": "8.3.2",
+ "ionicons": "^7.0.0",
+ "jsonc-parser": "^3.0.0",
+ "tslib": "^2.3.0"
+ },
+ "peerDependencies": {
+ "@angular/core": ">=16.0.0",
+ "@angular/forms": ">=16.0.0",
+ "@angular/router": ">=16.0.0",
+ "rxjs": ">=7.5.0",
+ "zone.js": ">=0.13.0"
+ }
+ },
+ "node_modules/@ionic/core": {
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.3.2.tgz",
+ "integrity": "sha512-ptiDXnn4131eKpY862lv7c9xxjly7vi4O+WWCES78E+hXHvTEAundcA5F8eQyb0MFIFvCnOxreTZjRJJnHqPYw==",
+ "license": "MIT",
+ "dependencies": {
+ "@stencil/core": "4.20.0",
+ "ionicons": "^7.2.2",
+ "tslib": "^2.1.0"
+ }
+ },
"node_modules/@ioredis/commands": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz",
diff --git a/package.json b/package.json
index b83ce5c59..0397b6fde 100644
--- a/package.json
+++ b/package.json
@@ -75,6 +75,7 @@
"@dfinity/principal": "0.15.7",
"@dinero.js/currencies": "2.0.0-alpha.8",
"@internationalized/number": "3.5.2",
+ "@ionic/angular": "^8.3.2",
"@nestjs/bull": "10.0.1",
"@nestjs/cache-manager": "2.2.2",
"@nestjs/common": "10.1.3",