src/app/shared/components/spatial-search-config/spatial-search-config.component.ts
Config popup for spatial search
changeDetection | ChangeDetectionStrategy.OnPush |
selector | ccf-spatial-search-config |
styleUrls | ./spatial-search-config.component.scss |
templateUrl | ./spatial-search-config.component.html |
Properties |
|
Inputs |
Outputs |
HostBindings |
organs | |
Type : OrganInfo[]
|
|
Selectable organs |
selectedOrgan | |
Type : OrganInfo
|
|
Currently selected organ |
sex | |
Type : Sex
|
|
Currently selected sex |
buttonClicked | |
Type : EventEmitter
|
|
Emits when the continue button is clicked |
closeDialog | |
Type : EventEmitter
|
|
Emits when the close button is clicked |
infoClicked | |
Type : EventEmitter
|
|
Emits when the info button is clicked |
updateOrgan | |
Type : EventEmitter
|
|
Emits when organ is updated |
updateSex | |
Type : EventEmitter
|
|
Emits when sex is updated |
class |
Type : "ccf-spatial-search-config"
|
Default value : 'ccf-spatial-search-config'
|
Readonly className |
Type : string
|
Default value : 'ccf-spatial-search-config'
|
Decorators :
@HostBinding('class')
|
import { ChangeDetectionStrategy, Component, EventEmitter, HostBinding, Input, Output } from '@angular/core';
import { OrganInfo } from 'ccf-shared';
/** Sex can either be male or female */
export type Sex = 'male' | 'female';
/**
* Config popup for spatial search
*/
@Component({
selector: 'ccf-spatial-search-config',
templateUrl: './spatial-search-config.component.html',
styleUrls: ['./spatial-search-config.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class SpatialSearchConfigComponent {
@HostBinding('class') readonly className = 'ccf-spatial-search-config';
/** Selectable organs */
@Input() organs!: OrganInfo[];
/** Currently selected organ */
@Input() selectedOrgan?: OrganInfo;
/** Currently selected sex */
@Input() sex!: Sex;
/** Emits when sex is updated */
@Output() readonly updateSex = new EventEmitter<Sex>();
/** Emits when organ is updated */
@Output() readonly updateOrgan = new EventEmitter<OrganInfo>();
/** Emits when the continue button is clicked */
@Output() readonly buttonClicked = new EventEmitter();
/** Emits when the close button is clicked */
@Output() readonly closeDialog = new EventEmitter();
/** Emits when the info button is clicked */
@Output() readonly infoClicked = new EventEmitter();
}
<div class="header">
<div class="header-left">
<div class="title">Configure Spatial Search</div>
<button class="info" mat-icon-button (click)="infoClicked.emit()">
<mat-icon>info</mat-icon>
</button>
</div>
<button class="close" mat-icon-button (click)="closeDialog.emit()">
<mat-icon>close</mat-icon>
</button>
</div>
<div class="sex-toggle">
<div class="label">Donor Sex:</div>
<mat-radio-group class="radio-group" [(ngModel)]="sex" (change)="updateSex.emit($event.value)">
<mat-radio-button class="radio" value="male">Male</mat-radio-button>
<mat-radio-button class="radio" value="female">Female</mat-radio-button>
</mat-radio-group>
</div>
<div class="organ-selector">
<div class="label">Select an organ</div>
<mat-form-field class="form-field" appearance="fill" subscriptSizing="dynamic">
<div *ngIf="!selectedOrgan" class="label">Organs</div>
<mat-select
disableOptionCentering="true"
panelClass="organ-select"
[(value)]="selectedOrgan"
(selectionChange)="updateOrgan.emit($event.value)"
hideSingleSelectionIndicator="true"
>
<mat-option class="organ-select-option" *ngFor="let organ of organs" [value]="organ">
{{ organ.name }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<button class="continue-button" [class.disabled]="!selectedOrgan" mat-button (click)="buttonClicked.emit()">
Continue
</button>
./spatial-search-config.component.scss
:host {
display: flex;
flex-direction: column;
align-items: flex-start;
padding: 2rem;
gap: 2rem;
width: 30.5rem;
box-shadow: 0px 25rem 25rem rgba(0, 0, 0, 0.16);
border-radius: 0.25rem;
font-size: 1rem;
.button {
cursor: pointer;
}
.header {
display: flex;
justify-content: space-between;
width: 100%;
font-size: 1.25rem;
align-items: center;
.header-left {
display: flex;
align-items: center;
.title {
margin-right: 1rem;
}
}
button {
padding: 0;
background: none;
border: none;
cursor: pointer;
outline: none;
border-radius: 0.25rem;
transition: 0.6s;
display: flex;
align-items: center;
justify-content: center;
}
}
.sex-toggle {
display: flex;
.label {
margin-right: 2rem;
line-height: 1.75rem;
}
.radio {
margin-right: 4rem;
::ng-deep .mdc-radio {
padding: 0;
padding-right: 0.5rem;
}
}
}
.organ-selector {
.label {
height: 0rem;
}
::ng-deep .mat-mdc-text-field-wrapper {
font-size: 1rem;
padding-bottom: 0.75rem;
padding-top: 3rem;
margin-left: 0.5rem;
width: 14rem;
.mat-mdc-form-field-infix {
padding: 0;
border-top: none;
}
.mdc-line-ripple {
bottom: 0rem;
height: 0.125rem;
}
.mat-mdc-select-arrow-wrapper {
transform: translatey(0rem);
}
}
}
.continue-button {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
padding: 0.25rem 1rem;
width: 14rem;
height: 2rem;
border-width: 1px;
border-style: solid;
border-radius: 0.25rem;
box-shadow: 0px 2px 6px rgba(0, 0, 0, 0.16);
&.disabled {
pointer-events: none;
opacity: 0.5;
}
}
}
::ng-deep .organ-select {
top: 2.5rem;
left: -0.25rem;
padding: 0 !important;
.organ-select-option {
height: 3.5rem;
border-bottom: 1px solid;
}
}