|
explanation
|
Type : string
|
|
|
optional tooltip to explain detailed meaning of this widget / statistic
|
|
loading
|
Type : boolean
|
Default value : false
|
|
|
Show a loading indicator until data is ready to be shown
|
|
title
|
Type : string | number
|
|
|
import { ChangeDetectionStrategy, Component, input } from "@angular/core";
import { IconName } from "@fortawesome/fontawesome-svg-core";
import { MatProgressSpinnerModule } from "@angular/material/progress-spinner";
import { FaDynamicIconComponent } from "../../common-components/fa-dynamic-icon/fa-dynamic-icon.component";
import { MatTooltipModule } from "@angular/material/tooltip";
export type DashboardTheme =
"general" | "child" | "attendance" | "note" | "class" | "school";
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: "app-dashboard-widget",
templateUrl: "./dashboard-widget.component.html",
styleUrls: ["./dashboard-widget.component.scss"],
imports: [MatProgressSpinnerModule, FaDynamicIconComponent, MatTooltipModule],
})
export class DashboardWidgetComponent {
subtitle = input<string>();
icon = input<IconName>();
theme = input<DashboardTheme>();
title = input<string | number>();
/** optional tooltip to explain detailed meaning of this widget / statistic */
explanation = input<string>();
headline = input<string>();
/** Show a loading indicator until data is ready to be shown */
loading = input(false);
}
<!-- Header -->
<div class="widget-header theme-background-{{ theme() }}">
@if (headline()) {
<div class="widget-headline">{{ headline() }}</div>
} @else {
<div class="widget-title">
@if (loading()) {
<mat-spinner diameter="40"></mat-spinner>
} @else {
{{ title() }}
}
</div>
<div class="widget-subheadline" [matTooltip]="explanation()">
{{ subtitle() }}
</div>
}
<app-fa-dynamic-icon
class="widget-icon"
[icon]="icon()"
></app-fa-dynamic-icon>
</div>
<!-- Content -->
<div class="widget-content">
@if (loading()) {
<h2 class="headline" i18n>Loading...</h2>
} @else {
<ng-content select="app-widget-content"></ng-content>
}
</div>
@use "@angular/material/core/style/elevation" as mat-elevation;
$widget-header-height: 64px;
$widget-content-height: 320px;
$font-size-headline: 40pt;
$padding-header: 24px;
$border-radius-card: 4px;
.widget-header {
/* Defines a grid that roughly looks like this:
* |-------|--------------------------------------|
* | | |
* | | |
* |-------|--------------------------------------|
* | | |
* |-------|--------------------------------------|
*
* The right-upper side is where the headline will be placed.
* On the lower right side, the subhead-line is placed
* On the two left sides, the icon will be placed in a
* centered way
*/
display: grid;
grid-template: 2fr 1fr / 40pt 1fr;
grid-template-areas:
"icon headline"
"subheadline subheadline";
padding: $padding-header;
height: $widget-header-height;
}
.widget-icon {
grid-area: icon;
color: white;
align-self: center;
font-size: $font-size-headline;
/* fixes the correct centering of this item */
display: table;
}
.widget-headline {
grid-area: headline;
text-align: end;
place-self: end;
font-size: 28pt;
color: white;
}
.widget-title {
grid-area: headline;
text-align: end;
place-self: center end;
font-size: 40pt;
color: white;
}
.widget-subheadline {
grid-area: subheadline;
text-align: end;
place-self: end;
margin-top: 8px;
font-size: 14px;
color: white;
}
.widget-content {
height: $widget-content-height;
overflow: hidden;
display: flex;
background-color: white;
}
.headline {
height: 100%;
width: 100%;
display: flex;
place-content: center;
place-items: center;
}
/* Map containing the colors that belong to a certain theme */
$themes: (
general: #555555,
child: #1565c0,
attendance: #00838f,
note: #008f53,
class: #2e7d32,
school: #9e9d24,
);
@each $ident, $color in $themes {
.theme-background-#{$ident} {
background-color: $color;
}
}
:host {
display: block;
border-radius: $border-radius-card;
/* necessary for the border-radius to apply */
overflow: auto;
@include mat-elevation.elevation(3);
}
Legend
Html element with directive