Skip to content

Commit d8c2aa4

Browse files
committed
feat: add UI skeleton for the dashboard page.
1 parent 3857f75 commit d8c2aa4

7 files changed

Lines changed: 456 additions & 64 deletions

File tree

package-lock.json

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"@angular/platform-browser": "^18.2.0",
1919
"@angular/platform-browser-dynamic": "^18.2.0",
2020
"@angular/router": "^18.2.0",
21+
"chart.js": "^4.4.8",
2122
"primeflex": "^3.3.1",
2223
"primeicons": "^7.0.0",
2324
"primeng": "^17.18.11",
Lines changed: 73 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,78 @@
1-
<div class="grid gap-3">
2-
<ng-container *ngFor="let item of cardItems">
3-
<ng-container *ngTemplateOutlet="cardTemplate; context: { $implicit: item }"></ng-container>
4-
</ng-container>
1+
<div *ngIf="isLoading" class="text-center p-4">
2+
<p-progressSpinner styleClass="w-4rem h-4rem" strokeWidth="8"></p-progressSpinner>
3+
<p>Loading dashboard...</p>
4+
</div>
5+
<div *ngIf="errorMessages.length > 0 && !isLoading" class="col-12">
6+
<p-messages [(value)]="errorMessages" [enableService]="false" [closable]="true"></p-messages>
57
</div>
68

7-
<ng-template #cardTemplate let-item>
8-
<div class="col flex-auto">
9-
<p-card class="custom-card">
10-
<div class="flex justify-content-between mb-3">
11-
<div>
12-
<span class="block text-muted-color font-medium mb-3">{{ item.title }}</span>
13-
<div class="text-surface-900 dark:text-surface-0 font-medium text-xl">{{ item.value }}</div>
14-
</div>
15-
<div class="flex align-items-center justify-content-center border-round" [ngClass]="item.bgColor"
16-
style="width: 2.5rem; height: 2.5rem;">
17-
<i class="{{ item.icon }} text-xl" [ngClass]="item.iconColor"></i>
9+
<div *ngIf="!isLoading && errorMessages.length === 0" class="dashboard-grid-container">
10+
11+
<div class="dashboard-row dashboard-row-1">
12+
<ng-container *ngFor="let item of dashboardCards">
13+
<p-card class="h-full">
14+
<div class="flex justify-content-between mb-3">
15+
<div>
16+
<span class="block text-muted-color font-medium mb-3">{{ item.title }}</span>
17+
<div class="text-surface-900 dark:text-surface-0 font-medium text-xl">{{ item.value }}</div>
18+
</div>
19+
<div class="flex align-items-center justify-content-center border-round" [ngClass]="item.bgColor"
20+
style="width: 2.5rem; height: 2.5rem;">
21+
<i class="{{ item.icon }} text-xl" [ngClass]="item.iconColor"></i>
22+
</div>
1823
</div>
19-
</div>
20-
<span class="text-primary font-medium">{{ item.stat }} </span>
21-
<span class="text-muted-color">{{ item.description }}</span>
24+
<span *ngIf="item.description" class="text-muted-color">{{ item.description }}</span>
25+
</p-card>
26+
</ng-container>
27+
</div>
28+
29+
<div class="dashboard-row dashboard-row-2">
30+
<p-card header="Project Completion Status" class="h-full">
31+
<ul class="list-none p-0 m-0">
32+
<li *ngFor="let project of projectCompletionStats; let isLast = last"
33+
class="flex flex-column md:flex-row md:align-items-center md:justify-content-between mb-4"
34+
[ngClass]="{'border-bottom-1 surface-border pb-3': !isLast}">
35+
<div class="mb-2 md:mb-0">
36+
<span class="block text-surface-900 dark:text-surface-0 font-medium mb-1">{{ project.name }}</span>
37+
<span class="text-muted-color text-sm">{{ project.taskCount }} Tasks</span>
38+
</div>
39+
<div class="flex align-items-center">
40+
<span class="text-surface-900 dark:text-surface-0 font-semibold mr-3">{{ project.percentage }}%</span>
41+
<p-progressBar [value]="project.percentage" [showValue]="false" styleClass="h-0.5rem w-8rem md:w-10rem"></p-progressBar>
42+
</div>
43+
</li>
44+
<li *ngIf="projectCompletionStats.length === 0">
45+
<span class="text-muted-color">No project data available.</span>
46+
</li>
47+
</ul>
48+
</p-card>
49+
50+
<p-card header="Task Status Overview" class="h-full flex flex-column align-items-center">
51+
<ng-template pTemplate="content">
52+
<p-chart type="doughnut" [data]="taskStatusChartData" [options]="taskStatusChartOptions" height="200px" width="700px"></p-chart>
53+
</ng-template>
2254
</p-card>
2355
</div>
24-
</ng-template>
56+
57+
<div class="dashboard-row dashboard-row-3">
58+
<p-card header="Recent Activity" class="h-full">
59+
<ul class="list-none p-0 m-0">
60+
<li *ngFor="let activity of recentActivities; let isLast = last"
61+
class="flex align-items-center py-3"
62+
[ngClass]="{'border-bottom-1 surface-border': !isLast}">
63+
<div class="w-3rem h-3rem flex align-items-center justify-content-center border-circle mr-3 flex-shrink-0" [ngClass]="activity.bgColor">
64+
<i class="{{ activity.icon }} text-xl" [ngClass]="activity.iconColor"></i>
65+
</div>
66+
<div class="flex-1">
67+
<span class="block text-surface-900 dark:text-surface-0" [innerHTML]="activity.summary"></span>
68+
<span class="text-muted-color text-sm">{{ activity.time }}</span>
69+
</div>
70+
</li>
71+
<li *ngIf="recentActivities.length === 0">
72+
<span class="text-muted-color">No recent activity.</span>
73+
</li>
74+
</ul>
75+
</p-card>
76+
</div>
77+
78+
</div>
Lines changed: 78 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,82 @@
1-
::ng-deep .custom-card .p-card-body {
2-
padding: 2rem;
3-
}
1+
$md: 768px;
2+
$lg: 992px;
43

5-
::ng-deep .custom-card .p-card-content {
6-
padding: 0;
7-
}
4+
$grid-gap: 2rem;
85

9-
.text-muted-color {
10-
color: #64748b;
11-
}
6+
:host {
7+
.dashboard-grid-container {
8+
display: grid;
9+
gap: $grid-gap;
10+
}
1211

13-
.text-surface-900 {
14-
--tw-text-opacity: 1;
15-
color: color-mix(in srgb, var(--surface-900) calc(100%* var(--tw-text-opacity, 1)), transparent);
12+
.dashboard-row {
13+
display: grid;
14+
gap: $grid-gap;
15+
}
16+
17+
.dashboard-row-1 {
18+
grid-template-columns: 1fr;
19+
20+
@media (min-width: $md) {
21+
grid-template-columns: repeat(2, 1fr);
22+
}
23+
24+
@media (min-width: $lg) {
25+
grid-template-columns: repeat(4, 1fr);
26+
}
27+
}
28+
29+
.dashboard-row-2 {
30+
grid-template-columns: 1fr;
31+
32+
@media (min-width: $md) {
33+
grid-template-columns: repeat(2, 1fr);
34+
}
35+
}
36+
37+
.dashboard-row-3 {
38+
grid-template-columns: 1fr;
39+
}
40+
41+
p-card {
42+
display: flex;
43+
flex-direction: column;
44+
height: 100%;
45+
}
46+
47+
::ng-deep .p-card {
48+
.p-card-body {
49+
display: flex;
50+
flex-direction: column;
51+
flex-grow: 1;
52+
padding: $grid-gap;
53+
}
54+
.p-card-content {
55+
flex-grow: 1;
56+
padding: 0;
57+
58+
&.center-chart-content {
59+
display: flex;
60+
justify-content: center;
61+
align-items: center;
62+
}
63+
}
64+
ul {
65+
margin: 0;
66+
padding: 0;
67+
list-style: none;
68+
}
69+
}
70+
71+
::ng-deep .p-progressbar {
72+
height: 0.5rem;
73+
background-color: var(--surface-border, #dee2e6);
74+
.p-progressbar-value {
75+
background: var(--primary-color);
76+
}
77+
}
78+
79+
.text-muted-color {
80+
color: var(--text-color-secondary, #6c757d);
81+
}
1682
}

0 commit comments

Comments
 (0)