Add ability to filter search results by category
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone Build is passing

This commit is contained in:
Garrett Mills 2021-02-15 19:35:28 -06:00
parent 72ab2064dd
commit 8c253ac283
Signed by: garrettmills
GPG Key ID: D2BF5FBA8298F246
3 changed files with 81 additions and 1 deletions

View File

@ -7,6 +7,16 @@
class="search-input" class="search-input"
(ionChange)="onSearchChange($event)" (ionChange)="onSearchChange($event)"
></ion-input> ></ion-input>
<div class="types">
<div
class="type"
*ngFor="let resultType of resultTypes" [ngClass]="(selectedType === resultType ? 'current-type' : '')"
(click)="filterView(resultType)"
>
<i class="assoc-icon" [ngClass]="typeIcons[resultType]" *ngIf="typeIcons[resultType]"></i>
{{ typeTitles[resultType] }}
</div>
</div>
</ion-header> </ion-header>
<div class="search-results" style="height: 100%; overflow-y: scroll;"> <div class="search-results" style="height: 100%; overflow-y: scroll;">
<ion-list *ngIf="!loading"> <ion-list *ngIf="!loading">

View File

@ -6,6 +6,28 @@
} }
} }
.types {
display: flex;
flex-wrap: wrap;
.type {
padding: 5px 20px;
&.current-type {
border: 1px solid #ccc;
border-radius: 30px;
}
&:hover {
cursor: pointer;
}
i {
margin-right: 5px;
}
}
}
.search-label { .search-label {
display: flex; display: flex;

View File

@ -29,13 +29,36 @@ export class SearchComponent implements OnInit {
@ViewChild('ionInput') ionInput: IonInput; @ViewChild('ionInput') ionInput: IonInput;
@Input() query = ''; @Input() query = '';
public results: BehaviorSubject<SearchResult[]> = new BehaviorSubject<SearchResult[]>([]); public results: BehaviorSubject<SearchResult[]> = new BehaviorSubject<SearchResult[]>([]);
public allResults: BehaviorSubject<SearchResult[]> = new BehaviorSubject<SearchResult[]>([]);
public loading = false; public loading = false;
public typeIcons = NodeTypeIcons; public typeIcons = NodeTypeIcons;
public allResultTypes = ['all', 'page', 'node', 'db', 'code', 'files'];
public resultTypes = ['all'];
public typeTitles = {
all: 'All',
page: 'Pages',
node: 'Nodes',
db: 'Databases',
code: 'Code',
files: 'Files',
};
public selectedType = 'all';
protected searchChangeDebounce = debounce(async ($event) => { protected searchChangeDebounce = debounce(async ($event) => {
const query = $event.detail.value; const query = $event.detail.value;
this.results.next(await this.search(query)); const results = await this.search(query);
this.allResults.next(results);
if ( !this.allResults.getValue() ) {
this.resultTypes = ['all'];
} else {
const existentTypes = this.allResults.getValue().map(x => this.classifyResult(x));
this.resultTypes = this.allResultTypes.filter((x: any) => existentTypes.includes(x) || x === 'all');
}
this.filterView(this.selectedType);
this.loading = false; this.loading = false;
}, 1000); }, 1000);
@ -50,6 +73,31 @@ export class SearchComponent implements OnInit {
await this.ionModalController.dismiss(); await this.ionModalController.dismiss();
} }
filterView(name: string) {
this.selectedType = name;
this.results.next((this.allResults.getValue() || []).filter(x => {
if ( this.selectedType === 'all' ) {
return true;
}
return this.classifyResult(x) === this.selectedType;
}));
}
classifyResult(result: SearchResult) {
if ( ['page', 'form'].includes(result.type) ) {
return 'page';
} else if ( ['node', 'markdown'].includes(result.type) ) {
return 'node';
} else if ( result.type === 'code' ) {
return 'code';
} else if ( result.type === 'db' ) {
return 'db';
} else if ( ['file_box', 'files'].includes(result.type) || result.type.startsWith('file_box') ) {
return 'files';
}
}
ngOnInit() { ngOnInit() {
setTimeout(() => { setTimeout(() => {
this.ionInput.setFocus(); this.ionInput.setFocus();