From b56eec2c0092c18e75b1dad7c9b6efa1f441d81f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Nagy?= Date: Fri, 20 Feb 2026 19:17:36 +0100 Subject: [PATCH 1/7] Add info-button --- .../info-button/info-button.component.ts | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 frontend/Exence/src/app/shared/info-button/info-button.component.ts diff --git a/frontend/Exence/src/app/shared/info-button/info-button.component.ts b/frontend/Exence/src/app/shared/info-button/info-button.component.ts new file mode 100644 index 0000000..a0c5ef1 --- /dev/null +++ b/frontend/Exence/src/app/shared/info-button/info-button.component.ts @@ -0,0 +1,29 @@ +import { Component, input } from '@angular/core'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { ButtonComponent } from '../button/button.component'; +import { StopPropagationDirective } from '../stop-propagation.directive'; + +@Component({ + selector: 'ex-info-button', + template: ` + + `, + styles: ` + :host { + position: absolute; + top: 1rem; + right: 1rem; + } + `, + imports: [ButtonComponent, MatTooltipModule, StopPropagationDirective], +}) +export class InfoButtonComponent { + tooltip = input.required(); +} From 79e02cdc1dc876aa5a87ebc2ca8afc1e498b517d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Nagy?= Date: Fri, 20 Feb 2026 20:59:29 +0100 Subject: [PATCH 2/7] Fix typos --- .../Exence/src/app/private/dashboard/dashboard.component.html | 2 +- .../Exence/src/app/private/profile/profile.component.html | 2 +- .../transactions-and-categories.component.html | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/Exence/src/app/private/dashboard/dashboard.component.html b/frontend/Exence/src/app/private/dashboard/dashboard.component.html index f1059e1..230e2fe 100644 --- a/frontend/Exence/src/app/private/dashboard/dashboard.component.html +++ b/frontend/Exence/src/app/private/dashboard/dashboard.component.html @@ -1,4 +1,4 @@ -
+

diff --git a/frontend/Exence/src/app/private/profile/profile.component.html b/frontend/Exence/src/app/private/profile/profile.component.html index ee9dd0f..cb5ac79 100644 --- a/frontend/Exence/src/app/private/profile/profile.component.html +++ b/frontend/Exence/src/app/private/profile/profile.component.html @@ -1,4 +1,4 @@ -
+
-
+
Date: Fri, 20 Feb 2026 22:08:41 +0100 Subject: [PATCH 3/7] #EX-296: Add stat-card.component design --- .../stat-card/stat-card.component.html | 43 +++++++++++++++++ .../stat-card/stat-card.component.scss | 47 +++++++++++++++++++ .../stat-card/stat-card.component.ts | 47 +++++++++++++++++++ 3 files changed, 137 insertions(+) create mode 100644 frontend/Exence/src/app/private/statistics/stat-card/stat-card.component.html create mode 100644 frontend/Exence/src/app/private/statistics/stat-card/stat-card.component.scss create mode 100644 frontend/Exence/src/app/private/statistics/stat-card/stat-card.component.ts diff --git a/frontend/Exence/src/app/private/statistics/stat-card/stat-card.component.html b/frontend/Exence/src/app/private/statistics/stat-card/stat-card.component.html new file mode 100644 index 0000000..c5049bc --- /dev/null +++ b/frontend/Exence/src/app/private/statistics/stat-card/stat-card.component.html @@ -0,0 +1,43 @@ + + + + @if (type() === 'metric') { +
+
{{ data().label }}
+
+ @switch (valueType()) { + @case ('currency') { + {{ data().value | currency: 'Ft' : 'symbol' : '1.0-0' }} + } + @case ('percentage') { + {{ data().value }}% + } + @default { + {{ data().value }} + } + } +
+
{{ data().contextLabel }}
+
+ } @else if (type() === 'spotlight') { +
+
+ {{ data().icon!.icon }} +
+
+
{{ data().label }}
+
{{ data().value | currency: 'Ft' : 'symbol' : '1.0-0' }}
+
"{{ data().contextLabel }}"
+
+
+ } + + @if (type() === 'metric') { +
+ @if (data().changePercentage !== 0) { + {{ assets().prefix + data().changePercentage }} + } + {{ assets().suffix }} +
+ } +
diff --git a/frontend/Exence/src/app/private/statistics/stat-card/stat-card.component.scss b/frontend/Exence/src/app/private/statistics/stat-card/stat-card.component.scss new file mode 100644 index 0000000..e099531 --- /dev/null +++ b/frontend/Exence/src/app/private/statistics/stat-card/stat-card.component.scss @@ -0,0 +1,47 @@ +$trend-colors: ( + 'UP': var(--tertiary-color), + 'DOWN': var(--error-color), + 'NEUTRAL': var(--accnet-text-color), +); + +:host { + max-width: 600px; + height: 100%; + flex-grow: 1; +} + +.trend { + position: absolute; + bottom: 1rem; + right: 1rem; + font-weight: bold; + display: flex; + flex-wrap: nowrap; + align-items: center; + + @each $trend, $color in $trend-colors { + &[trend='#{$trend}'] { + color: $color; + } + } + + mat-icon { + display: inline; + } +} + +mat-card.mat-mdc-card { + min-width: 350px; + width: 100%; + border: 2px solid var(--primary-color); + + [ex-card-icon] { + height: 5rem; + width: 5rem; + background-color: color-mix(in srgb, var(--icon-color), transparent 60%); + + mat-icon { + color: var(--icon-color); + } + } +} diff --git a/frontend/Exence/src/app/private/statistics/stat-card/stat-card.component.ts b/frontend/Exence/src/app/private/statistics/stat-card/stat-card.component.ts new file mode 100644 index 0000000..c14d02d --- /dev/null +++ b/frontend/Exence/src/app/private/statistics/stat-card/stat-card.component.ts @@ -0,0 +1,47 @@ +import { Component, computed, input } from '@angular/core'; +import { MatCardModule } from '@angular/material/card'; +import { MatIconModule } from '@angular/material/icon'; +import { InfoButtonComponent } from '../../../shared/info-button/info-button.component'; +import { CurrencyPipe } from '@angular/common'; +import { MaterialIcon } from '../../../data-model/modules/category/MaterialIcon'; + +export interface StatCardDTO { + label: string; + value: number; + changePercentage?: number; + trend?: 'UP' | 'DOWN' | 'NEUTRAL'; + contextLabel?: string; + icon?: { + icon: MaterialIcon; + color: string; + }; +} + +interface StatCardAssetInfo { + prefix: string; + suffix: string; +} + +@Component({ + selector: 'ex-stat-card', + templateUrl: './stat-card.component.html', + styleUrl: './stat-card.component.scss', + imports: [MatCardModule, MatIconModule, InfoButtonComponent, CurrencyPipe], +}) +export class StatCardComponent { + data = input.required(); + info = input.required(); + type = input<'metric' | 'spotlight'>('spotlight'); + valueType = input<'currency' | 'percentage'>('currency'); + + assets = computed(() => { + switch (this.data().trend) { + case 'UP': + return { prefix: '+', suffix: 'arrow_upward' }; + case 'DOWN': + return { prefix: '-', suffix: 'arrow_downward' }; + default: + return { prefix: '', suffix: 'check_indeterminate_small' }; + } + }); +} From 43f6323b2497ed44b8bc24abc7097077bb493b25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Nagy?= Date: Fri, 20 Feb 2026 22:08:48 +0100 Subject: [PATCH 4/7] #EX-296: Add empty-statistic-card.component --- .../empty-statistic-card.component.ts | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 frontend/Exence/src/app/private/statistics/empty-statistic-card.component.ts diff --git a/frontend/Exence/src/app/private/statistics/empty-statistic-card.component.ts b/frontend/Exence/src/app/private/statistics/empty-statistic-card.component.ts new file mode 100644 index 0000000..41ba3f4 --- /dev/null +++ b/frontend/Exence/src/app/private/statistics/empty-statistic-card.component.ts @@ -0,0 +1,49 @@ +import { Component } from '@angular/core'; +import { MatCardModule } from '@angular/material/card'; +import { MatIconModule } from '@angular/material/icon'; + +@Component({ + selector: 'ex-empty-statistic-card', + template: ` + + add_2 + + `, + styles: ` + :host { + cursor: pointer; + min-width: 350px; + max-width: 600px; + width: 100%; + height: 100%; + + &:hover { + mat-card.mat-mdc-card { + background-color: color-mix(in srgb, var(--app-card-color), white 5%); + transform: scale(1.015); + box-shadow: 1px 1px 10px var(--shadow-color); + } + } + &:active { + mat-card.mat-mdc-card { + transform: scale(1.015) translateY(3px); + } + } + } + + mat-card.mat-mdc-card { + transition: + background-color, + transform 0.3s ease-in-out; + height: 100%; + width: 100%; + border: 2px solid var(--primary-color); + } + + mat-icon { + color: var(--primary-color); + } + `, + imports: [MatCardModule, MatIconModule], +}) +export class EmptyStatisticCardComponent {} From 15863f9719d2ef8c9b38f0744470ecfde73c5c60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Nagy?= Date: Fri, 20 Feb 2026 22:27:54 +0100 Subject: [PATCH 5/7] #EX-296: Add statistic-card-list.component --- .../statistic-card-list.component.html | 5 +++++ .../statistic-card-list.component.scss | 13 +++++++++++++ .../statistic-card-list.component.ts | 12 ++++++++++++ 3 files changed, 30 insertions(+) create mode 100644 frontend/Exence/src/app/private/statistics/statistic-card-list/statistic-card-list.component.html create mode 100644 frontend/Exence/src/app/private/statistics/statistic-card-list/statistic-card-list.component.scss create mode 100644 frontend/Exence/src/app/private/statistics/statistic-card-list/statistic-card-list.component.ts diff --git a/frontend/Exence/src/app/private/statistics/statistic-card-list/statistic-card-list.component.html b/frontend/Exence/src/app/private/statistics/statistic-card-list/statistic-card-list.component.html new file mode 100644 index 0000000..96add72 --- /dev/null +++ b/frontend/Exence/src/app/private/statistics/statistic-card-list/statistic-card-list.component.html @@ -0,0 +1,5 @@ + + +@if (numberOfCards() < 4) { + +} diff --git a/frontend/Exence/src/app/private/statistics/statistic-card-list/statistic-card-list.component.scss b/frontend/Exence/src/app/private/statistics/statistic-card-list/statistic-card-list.component.scss new file mode 100644 index 0000000..23d1183 --- /dev/null +++ b/frontend/Exence/src/app/private/statistics/statistic-card-list/statistic-card-list.component.scss @@ -0,0 +1,13 @@ +:host { + display: flex; + flex-direction: row; + flex-wrap: nowrap; + align-items: center; + gap: 1.5rem; + + scrollbar-gutter: stable; + padding-bottom: 0.5rem; + + width: 100%; + overflow-x: auto; +} diff --git a/frontend/Exence/src/app/private/statistics/statistic-card-list/statistic-card-list.component.ts b/frontend/Exence/src/app/private/statistics/statistic-card-list/statistic-card-list.component.ts new file mode 100644 index 0000000..f0bee56 --- /dev/null +++ b/frontend/Exence/src/app/private/statistics/statistic-card-list/statistic-card-list.component.ts @@ -0,0 +1,12 @@ +import { Component, input } from '@angular/core'; +import { EmptyStatisticCardComponent } from '../empty-statistic-card.component'; + +@Component({ + selector: 'ex-statistic-card-list', + templateUrl: './statistic-card-list.component.html', + styleUrl: './statistic-card-list.component.scss', + imports: [EmptyStatisticCardComponent], +}) +export class StatisticCardListComponent { + numberOfCards = input.required(); +} From 0f0338378b1ad20252f53e4f33b22a412e29f056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Nagy?= Date: Fri, 20 Feb 2026 22:42:25 +0100 Subject: [PATCH 6/7] Small fix with spacing --- .../statistic-card-list/statistic-card-list.component.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/Exence/src/app/private/statistics/statistic-card-list/statistic-card-list.component.scss b/frontend/Exence/src/app/private/statistics/statistic-card-list/statistic-card-list.component.scss index 23d1183..af17f65 100644 --- a/frontend/Exence/src/app/private/statistics/statistic-card-list/statistic-card-list.component.scss +++ b/frontend/Exence/src/app/private/statistics/statistic-card-list/statistic-card-list.component.scss @@ -6,6 +6,7 @@ gap: 1.5rem; scrollbar-gutter: stable; + padding-top: 0.5rem; padding-bottom: 0.5rem; width: 100%; From be921322b730fd97d4b846895edfdc1e609f5f6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Nagy?= Date: Sat, 21 Feb 2026 22:35:27 +0100 Subject: [PATCH 7/7] Rename statistic-card-list to stat-card-list --- .../stat-card-list.component.html} | 0 .../stat-card-list.component.scss} | 0 .../stat-card-list.component.ts} | 8 ++++---- 3 files changed, 4 insertions(+), 4 deletions(-) rename frontend/Exence/src/app/private/statistics/{statistic-card-list/statistic-card-list.component.html => stat-card-list/stat-card-list.component.html} (100%) rename frontend/Exence/src/app/private/statistics/{statistic-card-list/statistic-card-list.component.scss => stat-card-list/stat-card-list.component.scss} (100%) rename frontend/Exence/src/app/private/statistics/{statistic-card-list/statistic-card-list.component.ts => stat-card-list/stat-card-list.component.ts} (55%) diff --git a/frontend/Exence/src/app/private/statistics/statistic-card-list/statistic-card-list.component.html b/frontend/Exence/src/app/private/statistics/stat-card-list/stat-card-list.component.html similarity index 100% rename from frontend/Exence/src/app/private/statistics/statistic-card-list/statistic-card-list.component.html rename to frontend/Exence/src/app/private/statistics/stat-card-list/stat-card-list.component.html diff --git a/frontend/Exence/src/app/private/statistics/statistic-card-list/statistic-card-list.component.scss b/frontend/Exence/src/app/private/statistics/stat-card-list/stat-card-list.component.scss similarity index 100% rename from frontend/Exence/src/app/private/statistics/statistic-card-list/statistic-card-list.component.scss rename to frontend/Exence/src/app/private/statistics/stat-card-list/stat-card-list.component.scss diff --git a/frontend/Exence/src/app/private/statistics/statistic-card-list/statistic-card-list.component.ts b/frontend/Exence/src/app/private/statistics/stat-card-list/stat-card-list.component.ts similarity index 55% rename from frontend/Exence/src/app/private/statistics/statistic-card-list/statistic-card-list.component.ts rename to frontend/Exence/src/app/private/statistics/stat-card-list/stat-card-list.component.ts index f0bee56..bf4b649 100644 --- a/frontend/Exence/src/app/private/statistics/statistic-card-list/statistic-card-list.component.ts +++ b/frontend/Exence/src/app/private/statistics/stat-card-list/stat-card-list.component.ts @@ -2,11 +2,11 @@ import { Component, input } from '@angular/core'; import { EmptyStatisticCardComponent } from '../empty-statistic-card.component'; @Component({ - selector: 'ex-statistic-card-list', - templateUrl: './statistic-card-list.component.html', - styleUrl: './statistic-card-list.component.scss', + selector: 'ex-stat-card-list', + templateUrl: './stat-card-list.component.html', + styleUrl: './stat-card-list.component.scss', imports: [EmptyStatisticCardComponent], }) -export class StatisticCardListComponent { +export class StatCardListComponent { numberOfCards = input.required(); }