Add advanced search
This commit is contained in:
parent
ad180b00cc
commit
f68a2599e9
5
frontend/package-lock.json
generated
5
frontend/package-lock.json
generated
@ -5338,6 +5338,11 @@
|
||||
"integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
|
||||
"dev": true
|
||||
},
|
||||
"hammerjs": {
|
||||
"version": "2.0.8",
|
||||
"resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz",
|
||||
"integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE="
|
||||
},
|
||||
"handle-thing": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
"@angular/platform-browser-dynamic": "~8.2.14",
|
||||
"@angular/router": "~8.2.14",
|
||||
"@ngx-translate/core": "^12.1.2",
|
||||
"hammerjs": "^2.0.8",
|
||||
"ngx-device-detector": "^1.4.5",
|
||||
"rxjs": "~6.4.0",
|
||||
"tslib": "^1.10.0",
|
||||
|
||||
@ -28,6 +28,8 @@ import {
|
||||
MatDialogModule,
|
||||
MatDividerModule,
|
||||
MatRadioModule,
|
||||
MatSliderModule,
|
||||
MatSlideToggleModule,
|
||||
MatStepperModule,
|
||||
MatTabsModule,
|
||||
MatTooltipModule
|
||||
@ -44,6 +46,7 @@ import {ShareButtonComponent} from './components/share-button/share-button.compo
|
||||
import {ShareDialogComponent} from './dialogs/share-dialog/share-dialog.component';
|
||||
import {TeamComponent} from './containers/team/team.component';
|
||||
import {DeviceDetectorModule} from 'ngx-device-detector';
|
||||
import {ToggleSliderComponent} from './components/toggle-slider/toggle-slider.component';
|
||||
|
||||
|
||||
@NgModule({
|
||||
@ -62,7 +65,8 @@ import {DeviceDetectorModule} from 'ngx-device-detector';
|
||||
BookmarkListComponent,
|
||||
ShareButtonComponent,
|
||||
ShareDialogComponent,
|
||||
TeamComponent
|
||||
TeamComponent,
|
||||
ToggleSliderComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
@ -89,7 +93,9 @@ import {DeviceDetectorModule} from 'ngx-device-detector';
|
||||
MatTabsModule,
|
||||
MatBadgeModule,
|
||||
MatStepperModule,
|
||||
MatRadioModule
|
||||
MatRadioModule,
|
||||
MatSlideToggleModule,
|
||||
MatSliderModule
|
||||
],
|
||||
providers: [],
|
||||
bootstrap: [AppComponent],
|
||||
|
||||
@ -1,42 +1,106 @@
|
||||
<mat-card class="search-container">
|
||||
|
||||
<span matCardTitle>Search</span>
|
||||
<mat-vertical-stepper>
|
||||
<mat-step>
|
||||
<ng-template matStepLabel>When is your trip?</ng-template>
|
||||
<div class="vertical-wrap">
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Start</mat-label>
|
||||
<input (change)="checkDates()" [(ngModel)]="from" [min]="today" matInput required type="date">
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>End</mat-label>
|
||||
<input (change)="checkDates()" [(ngModel)]="to" [min]="from" matInput required type="date">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</mat-step>
|
||||
<mat-step>
|
||||
<ng-template matStepLabel>What climate would you prefer?</ng-template>
|
||||
<div *ngFor="let key of multiPresetsKeys" class="sub-group">
|
||||
<span class="label">{{key|translate}}:</span><br>
|
||||
<mat-radio-group [ngModel]="multiPresetSelection[key]" [value]="undefined">
|
||||
<mat-radio-button
|
||||
#btn
|
||||
(click)="btn.checked = onMultiPresetSelect(preset)"
|
||||
*ngFor="let preset of multiPresets.get(key)"
|
||||
[value]="preset.preset_id"
|
||||
>{{preset.tag_label|translate}}</mat-radio-button>
|
||||
</mat-radio-group>
|
||||
</div>
|
||||
</mat-step>
|
||||
<mat-step>
|
||||
<ng-template matStepLabel>Whats most important to you?</ng-template>
|
||||
<div class="vertical">
|
||||
<mat-checkbox *ngFor="let preset of singlePresets"
|
||||
[(ngModel)]="singlePresetSelection[preset.preset_id]">{{preset.tag_label|translate}}</mat-checkbox>
|
||||
</div>
|
||||
</mat-step>
|
||||
</mat-vertical-stepper>
|
||||
<button (click)="onSearch()" [disabled]="!from || !to" class="search-btn" color="primary" mat-flat-button>Search
|
||||
|
||||
<mat-tab-group #tabGroup [animationDuration]="'0'" [selectedIndex]="selectedTab">
|
||||
|
||||
<!-- Guided Search Tab -->
|
||||
<mat-tab label="Guided">
|
||||
|
||||
<mat-vertical-stepper>
|
||||
|
||||
<mat-step>
|
||||
<ng-template matStepLabel>When is your trip?</ng-template>
|
||||
<div class="vertical-wrap">
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Start</mat-label>
|
||||
<input (change)="checkDates()" [(ngModel)]="from" [min]="today" matInput required type="date">
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>End</mat-label>
|
||||
<input (change)="checkDates()" [(ngModel)]="to" [min]="from" matInput required type="date">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</mat-step>
|
||||
|
||||
<mat-step>
|
||||
<ng-template matStepLabel>Which climate would you prefer?</ng-template>
|
||||
<div *ngFor="let key of multiPresetsKeys" class="sub-group">
|
||||
<span class="label">{{key|translate}}:</span><br>
|
||||
<mat-radio-group [ngModel]="multiPresetSelection[key]" [value]="undefined">
|
||||
<mat-radio-button
|
||||
#btn
|
||||
(click)="btn.checked = onMultiPresetSelect(preset)"
|
||||
*ngFor="let preset of multiPresets.get(key)"
|
||||
[value]="preset.preset_id"
|
||||
>{{preset.tag_label|translate}}</mat-radio-button>
|
||||
</mat-radio-group>
|
||||
</div>
|
||||
</mat-step>
|
||||
|
||||
<mat-step>
|
||||
<ng-template matStepLabel>What else is important to you?</ng-template>
|
||||
<div class="vertical">
|
||||
<mat-checkbox *ngFor="let preset of singlePresets"
|
||||
[(ngModel)]="singlePresetSelection[preset.preset_id]">{{preset.tag_label|translate}}</mat-checkbox>
|
||||
</div>
|
||||
</mat-step>
|
||||
</mat-vertical-stepper>
|
||||
</mat-tab>
|
||||
|
||||
<!-- Advanced Search Tab -->
|
||||
<mat-tab label="Advanced">
|
||||
<!-- Date -->
|
||||
<section class="group">
|
||||
<span class="title">Date</span>
|
||||
<div class=" content vertical-wrap">
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Start</mat-label>
|
||||
<input (change)="checkDates()" [(ngModel)]="from" [min]="today" matInput required type="date">
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>End</mat-label>
|
||||
<input (change)="checkDates()" [(ngModel)]="to" [min]="from" matInput required type="date">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Text Filter -->
|
||||
<section class="group">
|
||||
<span class="title">Text</span>
|
||||
<div class="content vertical-wrap">
|
||||
<mat-form-field class="text-input">
|
||||
<mat-label>Text search</mat-label>
|
||||
<input [(ngModel)]="textFilter" matInput>
|
||||
<button (click)="textFilter = ''" *ngIf="textFilter.length" mat-icon-button matSuffix>
|
||||
<mat-icon>clear</mat-icon>
|
||||
</button>
|
||||
</mat-form-field>
|
||||
<div class="horizontal space">
|
||||
<span>Search in description </span>
|
||||
<mat-slide-toggle [(ngModel)]="fullText"></mat-slide-toggle>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Climate Params -->
|
||||
<section class="group">
|
||||
<span class="title">Climate</span>
|
||||
<app-toggle-slider [(model)]="temperatureMeanMax" [label]="'Max Temp'" [max]="45" [min]="0"></app-toggle-slider>
|
||||
<app-toggle-slider [(model)]="precipitation" [label]="'Precipitation'" [max]="500"
|
||||
[min]="0"></app-toggle-slider>
|
||||
</section>
|
||||
<!-- Financial -->
|
||||
<section class="group">
|
||||
<span class="title">Fincancial</span>
|
||||
<app-toggle-slider [(model)]="accommodation" [label]="'Accommodation'" [max]="60" [min]="0"></app-toggle-slider>
|
||||
</section>
|
||||
|
||||
</mat-tab>
|
||||
|
||||
</mat-tab-group>
|
||||
|
||||
<button (click)="onSearch(tabGroup.selectedIndex === 1)" [disabled]="!from || !to" class="search-btn" color="primary"
|
||||
mat-flat-button>Search
|
||||
<mat-icon matSuffix>search</mat-icon>
|
||||
</button>
|
||||
|
||||
</mat-card>
|
||||
|
||||
@ -2,13 +2,6 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
> .group {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
> .search-btn {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
@ -34,6 +27,38 @@
|
||||
}
|
||||
}
|
||||
|
||||
.group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 1rem 0;
|
||||
|
||||
> .title {
|
||||
font-size: 1.2rem;
|
||||
font-weight: bold;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
> .content {
|
||||
margin: 0 2.5rem;
|
||||
|
||||
.text-input {
|
||||
min-width: 14rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.horizontal {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
&.space {
|
||||
> * {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.vertical {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@ -14,6 +14,9 @@ import {SearchService} from '../../services/search.service';
|
||||
})
|
||||
export class SearchInputComponent implements OnInit {
|
||||
|
||||
|
||||
selectedTab = 0;
|
||||
|
||||
presets: Preset[];
|
||||
singlePresets: Preset[];
|
||||
multiPresets: Map<string, Preset[]>;
|
||||
@ -21,9 +24,18 @@ export class SearchInputComponent implements OnInit {
|
||||
|
||||
from: string;
|
||||
to: string;
|
||||
|
||||
// Guided Search
|
||||
singlePresetSelection = {};
|
||||
multiPresetSelection = {};
|
||||
|
||||
// Advanced Search
|
||||
textFilter = '';
|
||||
fullText = false;
|
||||
temperatureMeanMax: number;
|
||||
precipitation: number;
|
||||
accommodation: number;
|
||||
|
||||
readonly today = this.from = formatDate(new Date(), 'yyyy-MM-dd', 'en-GB');
|
||||
|
||||
constructor(private router: Router, private ps: PresetService, private ss: SearchService) {
|
||||
@ -43,41 +55,13 @@ export class SearchInputComponent implements OnInit {
|
||||
this.multiPresets = this.ps.multiPresets;
|
||||
this.multiPresetsKeys = [...this.multiPresets.keys()];
|
||||
|
||||
const prevInput = this.ss.loadSearchInput();
|
||||
|
||||
if (prevInput) {
|
||||
this.from = prevInput.from;
|
||||
this.to = prevInput.to;
|
||||
this.singlePresetSelection = prevInput.singlePresetSelection;
|
||||
this.multiPresetSelection = prevInput.multiPresetSelection;
|
||||
}
|
||||
this.loadSearch();
|
||||
}
|
||||
|
||||
async onSearch() {
|
||||
const query: Query = {
|
||||
from: new Date(this.from).getTime(),
|
||||
to: new Date(this.to).getTime(),
|
||||
};
|
||||
|
||||
for (const preset of this.singlePresets) {
|
||||
if (this.singlePresetSelection[preset.preset_id]) {
|
||||
query[preset.parameter] = preset.value;
|
||||
}
|
||||
}
|
||||
|
||||
for (const key of this.multiPresetsKeys) {
|
||||
if (this.multiPresetSelection[key]) {
|
||||
query[key] = this.presets.find(preset => preset.preset_id === this.multiPresetSelection[key]).value;
|
||||
}
|
||||
}
|
||||
|
||||
this.ss.saveSearchInput({
|
||||
from: this.from,
|
||||
to: this.to,
|
||||
singlePresetSelection: this.singlePresetSelection,
|
||||
multiPresetSelection: this.multiPresetSelection
|
||||
});
|
||||
async onSearch(isAdvanced: boolean) {
|
||||
this.saveSearch(isAdvanced);
|
||||
|
||||
const query = isAdvanced ? this.getQueryFromAdvanced() : this.getQueryFromGuided();
|
||||
|
||||
await this.router.navigate(['/search'], {queryParams: {q: objToBase64(query)}});
|
||||
}
|
||||
@ -107,4 +91,76 @@ export class SearchInputComponent implements OnInit {
|
||||
this.to = formatDate(newToDate, 'yyyy-MM-dd', 'en-GB');
|
||||
}
|
||||
}
|
||||
|
||||
private getQueryFromGuided(): Query {
|
||||
const query: Query = {
|
||||
from: new Date(this.from).getTime(),
|
||||
to: new Date(this.to).getTime(),
|
||||
};
|
||||
|
||||
for (const preset of this.singlePresets) {
|
||||
if (this.singlePresetSelection[preset.preset_id]) {
|
||||
query[preset.parameter] = preset.value;
|
||||
}
|
||||
}
|
||||
|
||||
for (const key of this.multiPresetsKeys) {
|
||||
if (this.multiPresetSelection[key]) {
|
||||
query[key] = this.presets.find(preset => preset.preset_id === this.multiPresetSelection[key]).value;
|
||||
}
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
private getQueryFromAdvanced(): Query {
|
||||
const query: Query = {
|
||||
from: new Date(this.from).getTime(),
|
||||
to: new Date(this.to).getTime(),
|
||||
};
|
||||
|
||||
if (this.textFilter.length > 0) {
|
||||
query.fulltext = this.fullText;
|
||||
query.textfilter = this.textFilter;
|
||||
}
|
||||
|
||||
query.temperature_mean_max = this.temperatureMeanMax ? [this.temperatureMeanMax, this.temperatureMeanMax] : undefined;
|
||||
query.precipitation = this.precipitation ? [this.precipitation, this.precipitation] : undefined;
|
||||
query.accommodation_costs = this.accommodation ? [this.accommodation, this.accommodation] : undefined;
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
private saveSearch(isAdvanced: boolean) {
|
||||
this.ss.saveSearchInput({
|
||||
wasAdvanced: isAdvanced,
|
||||
from: this.from,
|
||||
to: this.to,
|
||||
singlePresetSelection: this.singlePresetSelection,
|
||||
multiPresetSelection: this.multiPresetSelection,
|
||||
fullText: this.fullText,
|
||||
textFiler: this.textFilter,
|
||||
tempMeanMax: this.temperatureMeanMax,
|
||||
precipitation: this.precipitation,
|
||||
accommodation: this.accommodation,
|
||||
});
|
||||
}
|
||||
|
||||
private loadSearch() {
|
||||
const prevInput = this.ss.loadSearchInput();
|
||||
|
||||
if (prevInput) {
|
||||
this.from = prevInput.from;
|
||||
this.to = prevInput.to;
|
||||
this.singlePresetSelection = prevInput.singlePresetSelection;
|
||||
this.multiPresetSelection = prevInput.multiPresetSelection;
|
||||
this.textFilter = prevInput.textFiler;
|
||||
this.fullText = prevInput.fullText;
|
||||
this.selectedTab = prevInput.wasAdvanced ? 1 : 0;
|
||||
this.temperatureMeanMax = prevInput.tempMeanMax;
|
||||
this.precipitation = prevInput.precipitation;
|
||||
this.accommodation = prevInput.accommodation;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
<span>{{label}}</span>
|
||||
<mat-slide-toggle (change)="onSlideToggleChange($event)" [(ngModel)]="enabled"></mat-slide-toggle>
|
||||
<mat-slider
|
||||
(click)="enabled=true"
|
||||
[(value)]="value"
|
||||
[disabled]="!enabled"
|
||||
[max]="max"
|
||||
[min]="min"
|
||||
[step]="step"
|
||||
[thumbLabel]="true"
|
||||
></mat-slider>
|
||||
@ -0,0 +1,22 @@
|
||||
:host {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
span {
|
||||
width: 33%;
|
||||
margin-right: 0.5rem;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
|
||||
}
|
||||
|
||||
mat-slide-toggle {
|
||||
flex: 0 1 auto;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
mat-slider {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
|
||||
import {ToggleSliderComponent} from './toggle-slider.component';
|
||||
|
||||
describe('ToggleSliderComponent', () => {
|
||||
let component: ToggleSliderComponent;
|
||||
let fixture: ComponentFixture<ToggleSliderComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ToggleSliderComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ToggleSliderComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,42 @@
|
||||
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
|
||||
import {MatSlideToggleChange} from '@angular/material';
|
||||
|
||||
@Component({
|
||||
selector: 'app-toggle-slider',
|
||||
templateUrl: './toggle-slider.component.html',
|
||||
styleUrls: ['./toggle-slider.component.scss']
|
||||
})
|
||||
export class ToggleSliderComponent implements OnInit {
|
||||
|
||||
enabled = false;
|
||||
rawValue: number;
|
||||
@Output() modelChange: EventEmitter<number> = new EventEmitter<number>();
|
||||
@Input() min = 0;
|
||||
@Input() max = 100;
|
||||
@Input() step = 1;
|
||||
@Input() label: string;
|
||||
|
||||
get value(): number {
|
||||
return this.rawValue;
|
||||
}
|
||||
|
||||
set value(value: number) {
|
||||
this.rawValue = value;
|
||||
this.modelChange.emit(value);
|
||||
}
|
||||
|
||||
@Input()
|
||||
set model(value: number) {
|
||||
this.rawValue = value;
|
||||
this.enabled = value !== undefined;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
onSlideToggleChange(event: MatSlideToggleChange) {
|
||||
if (event.checked === false) {
|
||||
this.modelChange.emit(undefined);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9,6 +9,10 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="results && results.length === 0" class="note">
|
||||
<mat-icon>error</mat-icon>
|
||||
<span>No match found!</span>
|
||||
</div>
|
||||
<div *ngIf="!results" class="spinner">
|
||||
<mat-spinner></mat-spinner>
|
||||
</div>
|
||||
|
||||
@ -15,6 +15,21 @@
|
||||
> app-result {
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.note {
|
||||
flex: 1 1 auto;
|
||||
align-self: center;
|
||||
font-size: 1.2rem;
|
||||
margin: 1.5rem;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
mat-icon {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.spinner {
|
||||
|
||||
@ -3,10 +3,16 @@ import {Result} from '../interfaces/result.interface';
|
||||
import {DataService} from './data.service';
|
||||
|
||||
export interface SearchInput {
|
||||
wasAdvanced: boolean;
|
||||
from: string;
|
||||
to: string;
|
||||
singlePresetSelection: object;
|
||||
multiPresetSelection: object;
|
||||
textFiler: string;
|
||||
fullText: boolean;
|
||||
tempMeanMax: number;
|
||||
precipitation: number;
|
||||
accommodation: number;
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
import {enableProdMode} from '@angular/core';
|
||||
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
import { environment } from './environments/environment';
|
||||
import {AppModule} from './app/app.module';
|
||||
import {environment} from './environments/environment';
|
||||
|
||||
import 'hammerjs';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
|
||||
@ -55,20 +55,20 @@ $travopti-green: (
|
||||
A400: #006400,
|
||||
A700: #004d00,
|
||||
contrast: (
|
||||
50: $dark-primary-text,
|
||||
100: $dark-primary-text,
|
||||
200: $dark-primary-text,
|
||||
300: $dark-primary-text,
|
||||
400: $dark-primary-text,
|
||||
500: $dark-primary-text,
|
||||
50: $light-primary-text,
|
||||
100: $light-primary-text,
|
||||
200: $light-primary-text,
|
||||
300: $light-primary-text,
|
||||
400: $light-primary-text,
|
||||
500: $light-primary-text,
|
||||
600: $light-primary-text,
|
||||
700: $light-primary-text,
|
||||
800: $light-primary-text,
|
||||
900: $light-primary-text,
|
||||
A100: $dark-primary-text,
|
||||
A200: $dark-primary-text,
|
||||
A400: $dark-primary-text,
|
||||
A700: $dark-primary-text,
|
||||
A100: $light-primary-text,
|
||||
A200: $light-primary-text,
|
||||
A400: $light-primary-text,
|
||||
A700: $light-primary-text,
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user