Pagina nueva
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import {HomepageComponent} from "./homepage/homepage.component";
|
||||
import {SearchComponent} from "./search/search.component";
|
||||
|
||||
|
||||
const routes: Routes = [
|
||||
{path: '', component: HomepageComponent}
|
||||
{path: '', component: HomepageComponent},
|
||||
{path: 'search', component: SearchComponent}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
||||
@@ -3,17 +3,19 @@ import { NgModule } from '@angular/core';
|
||||
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AppComponent } from './app.component';
|
||||
import { SearchHomeComponent } from './homepage/searchHome/searchHome.component';
|
||||
import { SearchBarComponent } from './homepage/searchBar/searchBar.component';
|
||||
import {HttpClientModule} from "@angular/common/http";
|
||||
import { HomepageComponent } from './homepage/homepage.component';
|
||||
import { NavComponent } from './nav/nav.component';
|
||||
import { SearchComponent } from './search/search.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
SearchHomeComponent,
|
||||
SearchBarComponent,
|
||||
HomepageComponent,
|
||||
NavComponent,
|
||||
SearchComponent,
|
||||
],
|
||||
imports: [
|
||||
HttpClientModule,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="hero-body">
|
||||
<div class="container">
|
||||
<h1 class="title">Busca la musica que disfrutas!</h1>
|
||||
<app-search></app-search>
|
||||
<app-search-bar></app-search-bar>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<div class="field has-addons">
|
||||
<div class="control is-expanded">
|
||||
<input #input class="input" type="search" (focus)="showList = true" (input)="searchTerm$.next(input.value)">
|
||||
<input #input class="input" type="search" (focus)="showList = true" [value]="query$.getValue()" (input)="query$.next(input.value)" (keyup.enter)="search()">
|
||||
</div>
|
||||
<div class="control">
|
||||
<a class="button is-white"><span class="icon"><i class="fas fa-search"></i></span></a>
|
||||
<a class="button" [class]="button_color"><span class="icon"><i class="fas fa-search"></i></span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -22,8 +22,10 @@
|
||||
</div>
|
||||
<div *ngFor="let result of discs" class="media disc">
|
||||
<figure class="media-left">
|
||||
<img *ngIf="result.cover_art" class="image is-64x64 cropped" src="{{result.cover_art.small}}" alt="{{result.title}} cover art">
|
||||
<img *ngIf="!result.cover_art" class="image is-64x64 cropped" src="../../../assets/svg/placeholder.svg" alt="{{result.title}} missing cover art">
|
||||
<img *ngIf="result.cover_art" class="image is-64x64 cropped" src="{{result.cover_art.small}}"
|
||||
alt="{{result.title}} cover art">
|
||||
<img *ngIf="!result.cover_art" class="image is-64x64 cropped" src="../../../assets/svg/placeholder.svg"
|
||||
alt="{{result.title}} missing cover art">
|
||||
</figure>
|
||||
<div class="media-content">
|
||||
<p>{{result.title}}</p>
|
||||
@@ -1,20 +1,20 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { SearchHomeComponent } from './searchHome.component';
|
||||
import { SearchBarComponent } from './searchBar.component';
|
||||
|
||||
describe('SearchComponent', () => {
|
||||
let component: SearchHomeComponent;
|
||||
let fixture: ComponentFixture<SearchHomeComponent>;
|
||||
let component: SearchBarComponent;
|
||||
let fixture: ComponentFixture<SearchBarComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ SearchHomeComponent ]
|
||||
declarations: [ SearchBarComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SearchHomeComponent);
|
||||
fixture = TestBed.createComponent(SearchBarComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
66
src/app/homepage/searchBar/searchBar.component.ts
Normal file
66
src/app/homepage/searchBar/searchBar.component.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import {Component, ElementRef, Input, OnInit, ViewChild} from '@angular/core';
|
||||
import {BehaviorSubject, forkJoin, Subject} from "rxjs";
|
||||
import {SearchService} from "../../services/search.service";
|
||||
import {Artist, Disc, Recording} from "../../models/brainz";
|
||||
import {Router} from "@angular/router";
|
||||
|
||||
@Component({
|
||||
selector: 'app-search-bar',
|
||||
templateUrl: './searchBar.component.html',
|
||||
styleUrls: ['./searchBar.component.scss']
|
||||
})
|
||||
export class SearchBarComponent implements OnInit {
|
||||
@ViewChild("input") input: ElementRef;
|
||||
showList: boolean;
|
||||
|
||||
artists: Artist[] = [];
|
||||
discs: Disc[] = [];
|
||||
recordings: Recording[] = [];
|
||||
|
||||
@Input() query$ = new BehaviorSubject<string>("");
|
||||
@Input() button_color = "is-white";
|
||||
@Input() autocomplete = true;
|
||||
|
||||
constructor(private searchService: SearchService, private router: Router) {
|
||||
}
|
||||
|
||||
|
||||
areResults() {
|
||||
return this.artists.length > 0 || this.discs.length > 0 || this.recordings.length > 0;
|
||||
}
|
||||
|
||||
show() {
|
||||
if (this.input.nativeElement === document.activeElement) return true;
|
||||
this.showList = false;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.query$.subscribe(() => {
|
||||
this.artists = [];
|
||||
this.discs = [];
|
||||
this.recordings = [];
|
||||
}
|
||||
);
|
||||
|
||||
let searchArtist = this.searchService.searchArtist(this.query$).subscribe((result) => {
|
||||
this.artists = result.artists;
|
||||
});
|
||||
let searchDisc = this.searchService.searchDisc(this.query$).subscribe((result) => {
|
||||
this.discs = result.discs;
|
||||
});
|
||||
let searchRecording = this.searchService.searchRecording(this.query$).subscribe((result) => {
|
||||
this.recordings = result.recordings;
|
||||
});
|
||||
}
|
||||
|
||||
search() {
|
||||
this.router.navigate(['search'], {
|
||||
state: {
|
||||
artists: this.artists,
|
||||
discs: this.discs,
|
||||
recordings: this.recordings
|
||||
},
|
||||
queryParams: {query: this.query$.getValue()}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
import {Component, ElementRef, OnInit, ViewChild} from '@angular/core';
|
||||
import {BehaviorSubject, forkJoin, Subject} from "rxjs";
|
||||
import {SearchService} from "../../search.service";
|
||||
import {Artist, Disc, Recording} from "../../models/brainz";
|
||||
|
||||
@Component({
|
||||
selector: 'app-search',
|
||||
templateUrl: './searchHome.component.html',
|
||||
styleUrls: ['./searchHome.component.scss']
|
||||
})
|
||||
export class SearchHomeComponent implements OnInit {
|
||||
@ViewChild("input") input: ElementRef;
|
||||
showList: boolean;
|
||||
|
||||
artists: Artist[] = [];
|
||||
discs: Disc[] = [];
|
||||
recordings: Recording[] = [];
|
||||
|
||||
searchTerm$ = new Subject<string>();
|
||||
|
||||
constructor(private searchService: SearchService) {
|
||||
}
|
||||
|
||||
|
||||
areResults() {
|
||||
return this.artists.length > 0 || this.discs.length > 0 || this.recordings.length > 0;
|
||||
}
|
||||
|
||||
show() {
|
||||
if (this.input.nativeElement === document.activeElement) return true;
|
||||
this.showList = false;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.searchTerm$.subscribe(() => {
|
||||
this.artists = [];
|
||||
this.discs = [];
|
||||
this.recordings = [];
|
||||
}
|
||||
);
|
||||
let searchArtist = this.searchService.searchArtist(this.searchTerm$).subscribe((result) => {
|
||||
this.artists = result.artists;
|
||||
});
|
||||
let searchDisc = this.searchService.searchDisc(this.searchTerm$).subscribe((result) => {
|
||||
this.discs = result.discs;
|
||||
});
|
||||
let searchRecording = this.searchService.searchRecording(this.searchTerm$).subscribe((result) => {
|
||||
this.recordings = result.recordings;
|
||||
});
|
||||
}
|
||||
}
|
||||
60
src/app/search/search.component.html
Normal file
60
src/app/search/search.component.html
Normal file
@@ -0,0 +1,60 @@
|
||||
<app-nav></app-nav>
|
||||
|
||||
<section class="hero">
|
||||
<div class="hero-body">
|
||||
<div class="container">
|
||||
<app-search-bar [query$]="query$" [autocomplete]="false" [button_color]="'is-primary'"></app-search-bar>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="container tabs is-boxed">
|
||||
<ul>
|
||||
<li [class.is-active]="artists_active" (click)="show_artist()">
|
||||
<a>
|
||||
<span class="icon is-small"><i class="fas fa-user" aria-hidden="true"></i></span>
|
||||
<span>Artistas</span>
|
||||
</a>
|
||||
</li>
|
||||
<li [class.is-active]="discs_active" (click)="show_discs()">
|
||||
<a>
|
||||
<span class="icon is-small"><i class="fas fa-compact-disc" aria-hidden="true"></i></span>
|
||||
<span>Discos</span>
|
||||
</a>
|
||||
</li>
|
||||
<li [class.is-active]="songs_active" (click)="show_songs()">
|
||||
<a>
|
||||
<span class="icon is-small"><i class="fas fa-music" aria-hidden="true"></i></span>
|
||||
<span>Canciones</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<ng-template [ngIf]="artists_active">
|
||||
<div class="container">
|
||||
<div class="media" *ngFor="let artist of artists">
|
||||
<div class="media-content">
|
||||
<p>{{artist.name}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
<ng-template [ngIf]="discs_active">
|
||||
<div class="container">
|
||||
<div class="media" *ngFor="let disc of discs">
|
||||
<div class="media-content">
|
||||
<p>{{disc.title}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
<ng-template [ngIf]="songs_active">
|
||||
<div class="container">
|
||||
<div class="media" *ngFor="let song of recordings">
|
||||
<div class="media-content">
|
||||
<p>{{song.title}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
0
src/app/search/search.component.scss
Normal file
0
src/app/search/search.component.scss
Normal file
25
src/app/search/search.component.spec.ts
Normal file
25
src/app/search/search.component.spec.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { SearchComponent } from './search.component';
|
||||
|
||||
describe('SearchComponent', () => {
|
||||
let component: SearchComponent;
|
||||
let fixture: ComponentFixture<SearchComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ SearchComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SearchComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
66
src/app/search/search.component.ts
Normal file
66
src/app/search/search.component.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {ActivatedRoute} from "@angular/router";
|
||||
import {SearchService} from "../services/search.service";
|
||||
import {map} from "rxjs/operators";
|
||||
import {Artist, Disc, Recording} from "../models/brainz";
|
||||
import {BehaviorSubject, Observable} from "rxjs";
|
||||
|
||||
@Component({
|
||||
selector: 'app-search',
|
||||
templateUrl: './search.component.html',
|
||||
styleUrls: ['./search.component.scss']
|
||||
})
|
||||
export class SearchComponent implements OnInit {
|
||||
query$ = new BehaviorSubject<string>("");
|
||||
|
||||
artists: Artist[] = [];
|
||||
discs: Disc[] = [];
|
||||
recordings: Recording[] = [];
|
||||
|
||||
artists_active = true;
|
||||
discs_active = false;
|
||||
songs_active= false;
|
||||
|
||||
constructor(private route: ActivatedRoute, private searchService: SearchService) {
|
||||
this.route.queryParams.pipe(map(params => params['query'] as string)).subscribe((query) => {
|
||||
this.query$.next(query);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.query$.subscribe(() => {
|
||||
this.artists = [];
|
||||
this.discs = [];
|
||||
this.recordings = [];
|
||||
});
|
||||
|
||||
this.searchService.searchArtist(this.query$).subscribe((result) => this.artists = result.artists);
|
||||
this.searchService.searchDisc(this.query$).subscribe((result) => this.discs = result.discs);
|
||||
this.searchService.searchRecording(this.query$).subscribe((result) => this.recordings = result.recordings);
|
||||
}
|
||||
|
||||
show_artist() {
|
||||
if(this.artists_active) return;
|
||||
|
||||
this.artists_active = true;
|
||||
this.discs_active = false;
|
||||
this.songs_active = false;
|
||||
}
|
||||
|
||||
show_discs() {
|
||||
if(this.discs_active) return;
|
||||
|
||||
this.artists_active = false;
|
||||
this.discs_active = true;
|
||||
this.songs_active = false;
|
||||
}
|
||||
|
||||
show_songs() {
|
||||
if(this.songs_active) return;
|
||||
|
||||
this.artists_active = false;
|
||||
this.discs_active = false;
|
||||
this.songs_active = true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import {Injectable} from '@angular/core';
|
||||
import {forkJoin, merge, Observable, of} from "rxjs";
|
||||
import {HttpClient} from "@angular/common/http";
|
||||
import {debounceTime, distinctUntilChanged, switchMap, tap} from "rxjs/operators";
|
||||
import {ArtistSearch, DiscSearch, RecordingSearch} from "./models/brainz";
|
||||
import {ArtistSearch, DiscSearch, RecordingSearch} from "../models/brainz";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
@@ -13,39 +13,39 @@ export class SearchService {
|
||||
constructor(private http: HttpClient) {
|
||||
}
|
||||
|
||||
searchArtist(terms: Observable<string>): Observable<ArtistSearch> {
|
||||
searchArtist(terms: Observable<string>, page: number = 1): Observable<ArtistSearch> {
|
||||
return terms.pipe(
|
||||
debounceTime(400),
|
||||
distinctUntilChanged(),
|
||||
switchMap(term => this.searchArtistQuery(term))
|
||||
switchMap(term => this.searchArtistQuery(term, page))
|
||||
);
|
||||
}
|
||||
|
||||
searchDisc(terms: Observable<string>): Observable<DiscSearch> {
|
||||
searchDisc(terms: Observable<string>, page: number = 1): Observable<DiscSearch> {
|
||||
return terms.pipe(
|
||||
debounceTime(400),
|
||||
distinctUntilChanged(),
|
||||
switchMap(term => this.searchDiscQuery(term))
|
||||
switchMap(term => this.searchDiscQuery(term, page))
|
||||
);
|
||||
}
|
||||
|
||||
searchRecording(terms: Observable<string>): Observable<RecordingSearch> {
|
||||
searchRecording(terms: Observable<string>, page: number = 1): Observable<RecordingSearch> {
|
||||
return terms.pipe(
|
||||
debounceTime(400),
|
||||
distinctUntilChanged(),
|
||||
switchMap(term => this.searchRecordingQuery(term))
|
||||
switchMap(term => this.searchRecordingQuery(term, page))
|
||||
);
|
||||
}
|
||||
|
||||
private searchArtistQuery(term: string): Observable<ArtistSearch> {
|
||||
private searchArtistQuery(term: string, page: number): Observable<ArtistSearch> {
|
||||
if (!term) {
|
||||
return of({paginate: {total: 0, current_page: 0, last_page: 0, per_page: 0}, artists: []} as ArtistSearch);
|
||||
}
|
||||
|
||||
return this.http.get<ArtistSearch>(`${this.baseUrl}/artist?query=${term}`);
|
||||
return this.http.get<ArtistSearch>(`${this.baseUrl}/artist?query=${term}&page=${page}`);
|
||||
}
|
||||
|
||||
private searchDiscQuery(term: string): Observable<DiscSearch> {
|
||||
private searchDiscQuery(term: string, page: number): Observable<DiscSearch> {
|
||||
if (!term) {
|
||||
return of({paginate: {total: 0, current_page: 0, last_page: 0, per_page: 0}, discs: []} as DiscSearch);
|
||||
}
|
||||
@@ -53,7 +53,7 @@ export class SearchService {
|
||||
return this.http.get<DiscSearch>(`${this.baseUrl}/disc?query=${term}`);
|
||||
}
|
||||
|
||||
private searchRecordingQuery(term: string): Observable<RecordingSearch> {
|
||||
private searchRecordingQuery(term: string, page: number): Observable<RecordingSearch> {
|
||||
if (!term) {
|
||||
return of({paginate: {total: 0, current_page: 0, last_page: 0, per_page: 0}, recordings: []} as RecordingSearch);
|
||||
}
|
||||
Reference in New Issue
Block a user