Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resources are shuffled on page load and a random button #106

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 15 additions & 3 deletions src/app/app.component.html
Expand Up @@ -29,9 +29,21 @@ <h1>Hacktoberfest 2019: Favorite Angular Resources</h1>
</mat-toolbar>
<mat-sidenav-container>
<mat-sidenav-content>
<mat-form-field>
<input matInput placeholder="Search for a resource" (*input)="input$" [value]="query$ | async" autocomplete="off">
</mat-form-field>
<div style="display: flex; align-items: center;">
<div style="text-align: center; padding-right: 1em;">
<button mat-fab color="accent" (click)="randomizeResources()">
<mat-icon
aria-hidden="false"
aria-label="Randomize"
>autorenew</mat-icon>
</button>
<!-- <br />
Randomize -->
</div>
<mat-form-field style="flex-grow: 1;">
<input matInput placeholder="Search for a resource" (*input)="input$" [value]="query$ | async" autocomplete="off">
</mat-form-field>
</div>

<ng-container *ngIf="{
columns: columns$ | async,
Expand Down
11 changes: 9 additions & 2 deletions src/app/app.component.ts
Expand Up @@ -17,7 +17,7 @@ import { trigger, transition, query, stagger, animate, style } from '@angular/an
transition('* => *', [
query(':enter' , [
style({ opacity: 0, transform: 'scale(.7)' }),
stagger(100, [
stagger(0, [
animate('0.3s', style({ opacity: 1, transform: 'scale(1)' }))
])
], { optional: true })
Expand Down Expand Up @@ -46,11 +46,18 @@ export class AppComponent implements OnInit {
'book': '📖'
};

constructor(private resourcesService: ResourcesService, private breakpointObserver: BreakpointObserver) { }
constructor(
private resourcesService: ResourcesService,
private breakpointObserver: BreakpointObserver,
) {}

ngOnInit() {
this.input$.pipe(
map(evt => (evt.target as HTMLInputElement).value)
).subscribe(query => this.resourcesService.search(query));
}

randomizeResources() {
this.resourcesService.randomizeResources();
}
}
51 changes: 46 additions & 5 deletions src/app/resources.service.ts
@@ -1,27 +1,53 @@
import { Injectable } from '@angular/core';
import { Router, ActivatedRoute, NavigationEnd } from '@angular/router';
import { BehaviorSubject } from 'rxjs';
import { Router, ActivatedRoute, NavigationEnd, Params } from '@angular/router';
import { BehaviorSubject, Subject, Observable } from 'rxjs';
import { map, pluck, filter, withLatestFrom, take, skip, debounceTime } from 'rxjs/operators';

import { resources } from '../assets/resources.json';

export interface Resource {
title: string,
description: string,
author: {
name: string
profile?: string
},
url: string,
category: string,
contributor: {
name: string,
profile?: string
}
};

@Injectable({
providedIn: 'root'
})
export class ResourcesService {
private routeQuery = this.route.queryParams.pipe(pluck('query'));
private resources: Resource[] = [...resources];

private queryParams = new BehaviorSubject<Params>({});
private routeQuery = this.queryParams.pipe(pluck('query'));
private placeholder = { title: 'placeholder', description: '', author: { name: '' }, contributor: { name: '' }, category: '', url: '' };

// https://stackoverflow.com/a/12646864
private shuffleArray(array: any[]) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
}

querySubject$ = new BehaviorSubject<string>('');
query$ = this.querySubject$.pipe(skip(1));
resources$ = this.routeQuery.pipe(
map(query => {
if (!query) {
return resources.concat(this.placeholder as any);
return this.resources.concat(this.placeholder as any);
}

const queryLower = query.toLowerCase();
return resources.filter(resource =>
return this.resources.filter(resource =>
resource.title.toLowerCase().includes(queryLower) ||
resource.description.toLowerCase().includes(queryLower) ||
resource.author.name.toLowerCase().includes(queryLower) ||
Expand All @@ -32,7 +58,22 @@ export class ResourcesService {
})
);

randomizeResources() {
this.shuffleArray(this.resources);
this.queryParams.pipe(take(1)).subscribe(queryParams=>{
this.queryParams.next(queryParams);
});
}

constructor(private router: Router, private route: ActivatedRoute) {
this.randomizeResources();

this.route.queryParams.subscribe({
next: x=>this.queryParams.next(x),
error: x=>this.queryParams.error(x),
complete: ()=>this.queryParams.complete(),
});

this.router.events
.pipe(
filter(evt => evt instanceof NavigationEnd),
Expand Down
14 changes: 14 additions & 0 deletions src/assets/resources.json
Expand Up @@ -1123,6 +1123,20 @@
"name": "Valerio Pisapia",
"profile": "https://www.linkedin.com/in/valerio-pisapia/"
}
},
{
"title": "Material Web Components for Angular",
"description": "Incorporating Google Material Components for a faithful and accurate representation of Material Design as envisioned on the web platform.",
"author": {
"name": "Dominic Carretto",
"profile": "https://github.com/trimox"
},
"url": "https://github.com/trimox/angular-mdc-web",
"category": "library",
"contributor": {
"name": "Maki",
"profile": "https://github.com/makitsune"
}
}
]
}
2 changes: 1 addition & 1 deletion src/styles.scss
Expand Up @@ -83,7 +83,7 @@ $theme: mat-dark-theme($primary, $accent);
$accent: map-get($theme, accent);

.hacktoberfest {
* {
* :not(.material-icons) {
font-family: 'Space Mono', monospace !important;
}

Expand Down