src/app/pages/current-team/current-team.component.ts
Page component for displaying current team members
| changeDetection | ChangeDetectionStrategy.OnPush |
| providers |
CurrentTeamStore
|
| selector | cns-current-team |
| imports |
HraCommonModule
ButtonsModule
FilterMenuComponent
FooterComponent
GalleryGridComponent
GalleryGridItemDirective
IconsModule
LinkDirective
MatButtonToggleModule
MatFormFieldModule
MatSelectModule
MatSidenavModule
NoResultsIndicatorComponent
ProfileCardComponent
ScrollingModule
SearchFilterComponent
SectionLinkComponent
|
| templateUrl | ./current-team.component.html |
| styleUrl | ./current-team.component.scss |
Properties |
|
Inputs |
constructor()
|
|
Initializes the component and store with route data
|
| data | |
Type : PeopleData
|
|
| Required : true | |
|
Team members data from route resolver |
|
| Protected Readonly placeholderImage |
Type : string
|
Default value : '/assets/placeholder-images/placeholder.png'
|
|
Gender neutral placeholder image for members without pictures |
| Protected Readonly sidebarStore |
Type : unknown
|
Default value : inject(SidebarStore)
|
|
Sidebar store for managing sidebar state |
| Protected Readonly store |
Type : unknown
|
Default value : inject(CurrentTeamStore)
|
|
Store for managing team member state and filters |
import { ChangeDetectionStrategy, Component, effect, inject, input, viewChild } from '@angular/core';
import { MatButtonToggleModule } from '@angular/material/button-toggle';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatSelectModule } from '@angular/material/select';
import { MatSidenav, MatSidenavModule } from '@angular/material/sidenav';
import { HraCommonModule } from '@hra-ui/common';
import { LinkDirective } from '@hra-ui/common/router-ext';
import { ButtonsModule } from '@hra-ui/design-system/buttons';
import { ProfileCardComponent } from '@hra-ui/design-system/cards/profile-card';
import { SectionLinkComponent } from '@hra-ui/design-system/content-templates/section-link';
import { FilterMenuComponent } from '@hra-ui/design-system/filter-menu';
import { GalleryGridComponent, GalleryGridItemDirective } from '@hra-ui/design-system/gallery-grid';
import { IconsModule } from '@hra-ui/design-system/icons';
import { NoResultsIndicatorComponent } from '@hra-ui/design-system/indicators/no-results-indicator';
import { ScrollingModule } from '@hra-ui/design-system/scrolling';
import { SearchFilterComponent } from '@hra-ui/design-system/search-filter';
import { FooterComponent } from '../../components/footer/footer.component';
import { PeopleData } from '../../schemas/people.schema';
import { SidebarStore } from '../../state/sidebar/sidebar.store';
import { CurrentTeamStore } from './state/current-team.store';
/**
* Page component for displaying current team members
*/
@Component({
selector: 'cns-current-team',
imports: [
HraCommonModule,
ButtonsModule,
FilterMenuComponent,
FooterComponent,
GalleryGridComponent,
GalleryGridItemDirective,
IconsModule,
LinkDirective,
MatButtonToggleModule,
MatFormFieldModule,
MatSelectModule,
MatSidenavModule,
NoResultsIndicatorComponent,
ProfileCardComponent,
ScrollingModule,
SearchFilterComponent,
SectionLinkComponent,
],
templateUrl: './current-team.component.html',
styleUrl: './current-team.component.scss',
providers: [CurrentTeamStore],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CurrentTeamComponent {
/**
* Team members data from route resolver
*/
readonly data = input.required<PeopleData>();
/** Store for managing team member state and filters */
protected readonly store = inject(CurrentTeamStore);
/** Sidebar store for managing sidebar state */
protected readonly sidebarStore = inject(SidebarStore);
/** Gender neutral placeholder image for members without pictures */
protected readonly placeholderImage = '/assets/placeholder-images/placeholder.png';
/** Reference to the sidebar component */
private readonly sidebar = viewChild.required(MatSidenav);
/**
* Initializes the component and store with route data
* - Sets people data from route resolver
*/
constructor() {
this.store.setPeople(this.data);
effect((onCleanup) => {
this.sidebarStore.setSidebar(this.sidebar());
onCleanup(() => this.sidebarStore.clearSidebar());
});
}
}
<mat-sidenav-container class="container">
<mat-sidenav
class="sidebar"
aria-label="Filter team members"
[mode]="sidebarStore.mode()"
[opened]="sidebarStore.isOpen()"
[disableClose]="sidebarStore.mode() === 'side'"
(closedStart)="sidebarStore.close()"
>
<hra-filter-menu
class="filters"
tagline="People at the Cyberinfrastructure for Network Science Center"
[filters]="store.filters()"
(filtersChange)="store.setFilters($event)"
>
<mat-button-toggle-group
hraButtonToggleSize="medium"
class="team-toggle"
aria-label="Select team"
[value]="store.team()"
(valueChange)="store.setTeam($event)"
>
<mat-button-toggle value="current">Current team</mat-button-toggle>
<mat-button-toggle value="past">Former team</mat-button-toggle>
</mat-button-toggle-group>
<mat-form-field class="sort-by" subscriptSizing="dynamic">
<mat-icon class="select-icon" matPrefix>sort</mat-icon>
<mat-label>Sort by</mat-label>
<mat-select [value]="store.sortBy()" (valueChange)="store.setSortBy($event)">
@if (store.team() === 'current') {
<mat-option value="hierarchical">Hierarchical</mat-option>
}
<mat-option value="lastNameAsc">Last name (ascending A-Z)</mat-option>
<mat-option value="lastNameDesc">Last name (descending Z-A)</mat-option>
<mat-option value="endYearNewest">End year (new to old)</mat-option>
<mat-option value="startYearOldest">Start year (old to new)</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="group-by" subscriptSizing="dynamic">
<mat-icon class="select-icon" matPrefix>category</mat-icon>
<mat-label>Group by</mat-label>
<mat-select [value]="store.groupBy()" (valueChange)="store.setGroupBy($event)">
<mat-option [value]="null">None</mat-option>
<mat-option value="role">Role</mat-option>
<mat-option value="startYear">Start year</mat-option>
<mat-option value="endYear">End year</mat-option>
</mat-select>
</mat-form-field>
</hra-filter-menu>
</mat-sidenav>
<mat-sidenav-content role="main">
<ng-scrollbar>
<div class="content">
<div class="search-bar">
<hra-search-filter
label="Search"
separator="/"
[totalCount]="store.numFilteredByTeam()"
[viewingCount]="store.numFilteredPeople()"
[search]="store.search() ?? ''"
(searchChange)="store.setSearch($event)"
/>
</div>
<div class="profile-list">
@if (store.numFilteredPeople() === 0) {
<hra-no-results-indicator (clearFilters)="store.resetFilters()" />
} @else {
@for (group of store.sortedGroupedPeople(); track group.label) {
<section class="section">
@if (group.label) {
<h3 hra-section-link class="title" [underlined]="true">{{ group.label }}</h3>
}
<hra-gallery-grid class="gallery" [dataSource]="group.people">
<hra-profile-card
*hraGalleryGridItem="let person"
[pictureUrl]="person.image ? person.image : placeholderImage"
[name]="person.name"
[description]="store.getMemberTitle(person)"
[centerContent]="true"
>
@if (store.team() === 'current') {
<a
mat-button
hraHyperlink
class="learn-more"
[hraLink]="`/people/${person.slug}`"
[attr.aria-label]="`Learn more about ${person.name}`"
>
Learn more
<mat-icon iconPositionEnd>arrow_right_alt</mat-icon>
</a>
}
</hra-profile-card>
</hra-gallery-grid>
</section>
}
}
</div>
<cns-footer class="footer" />
</div>
</ng-scrollbar>
</mat-sidenav-content>
</mat-sidenav-container>