| @@ -4,7 +4,6 @@ import { FormsModule } from '@angular/forms'; | |||
| import { AppRoutingModule } from './app-routing.module'; | |||
| import { AppComponent } from './app.component'; | |||
| import { HeaderComponent } from './misc/header/header.component'; | |||
| import { FooterComponent } from './misc/footer/footer.component'; | |||
| import { NewsDashboardComponent } from './news/news-dashboard/news-dashboard.component'; | |||
| import { HttpClientModule } from '@angular/common/http'; | |||
| @@ -19,7 +18,6 @@ import { NewsTeaserComponent } from './news/news-teaser/news-teaser.component'; | |||
| @NgModule({ | |||
| declarations: [ | |||
| AppComponent, | |||
| HeaderComponent, | |||
| FooterComponent, | |||
| NewsDashboardComponent, | |||
| TopNewsDashboardComponent, | |||
| @@ -1,9 +0,0 @@ | |||
| @import "../../../variables.scss"; | |||
| .header { | |||
| color: white; | |||
| background: transparent; | |||
| margin: 0px; | |||
| font-size: 30px; | |||
| padding: 1em 1em; | |||
| } | |||
| @@ -1,25 +0,0 @@ | |||
| import { async, ComponentFixture, TestBed } from '@angular/core/testing'; | |||
| import { HeaderComponent } from './header.component'; | |||
| describe('HeaderComponent', () => { | |||
| let component: HeaderComponent; | |||
| let fixture: ComponentFixture<HeaderComponent>; | |||
| beforeEach(async(() => { | |||
| TestBed.configureTestingModule({ | |||
| declarations: [ HeaderComponent ] | |||
| }) | |||
| .compileComponents(); | |||
| })); | |||
| beforeEach(() => { | |||
| fixture = TestBed.createComponent(HeaderComponent); | |||
| component = fixture.componentInstance; | |||
| fixture.detectChanges(); | |||
| }); | |||
| it('should create', () => { | |||
| expect(component).toBeTruthy(); | |||
| }); | |||
| }); | |||
| @@ -1,16 +0,0 @@ | |||
| import { Component, OnInit } from '@angular/core'; | |||
| import { faNewspaper } from '@fortawesome/free-solid-svg-icons'; | |||
| @Component({ | |||
| selector: 'app-header', | |||
| templateUrl: './header.component.html', | |||
| styleUrls: ['./header.component.scss'] | |||
| }) | |||
| export class HeaderComponent implements OnInit { | |||
| faNewspaper = faNewspaper; | |||
| constructor() { } | |||
| ngOnInit(): void { | |||
| } | |||
| } | |||
| @@ -1,111 +1,128 @@ | |||
| @-webkit-keyframes slide-in-right { | |||
| 0% { | |||
| from { | |||
| -webkit-transform: translateX(1000px); | |||
| transform: translateX(1000px); | |||
| } | |||
| 100% { | |||
| to { | |||
| visibility: visible; | |||
| -webkit-transform: translateX(0); | |||
| transform: translateX(0); | |||
| } | |||
| } | |||
| @keyframes slide-in-right { | |||
| 0% { | |||
| from { | |||
| -webkit-transform: translateX(1000px); | |||
| transform: translateX(1000px); | |||
| } | |||
| 100% { | |||
| to { | |||
| visibility: visible; | |||
| -webkit-transform: translateX(0); | |||
| transform: translateX(0); | |||
| } | |||
| } | |||
| @-webkit-keyframes slide-in-left { | |||
| 0% { | |||
| from { | |||
| -webkit-transform: translateX(-1000px); | |||
| transform: translateX(-1000px); | |||
| } | |||
| 100% { | |||
| to { | |||
| visibility: visible; | |||
| -webkit-transform: translateX(0); | |||
| transform: translateX(0); | |||
| } | |||
| } | |||
| @keyframes slide-in-left { | |||
| 0% { | |||
| from { | |||
| -webkit-transform: translateX(-1000px); | |||
| transform: translateX(-1000px); | |||
| } | |||
| 100% { | |||
| to { | |||
| visibility: visible; | |||
| -webkit-transform: translateX(0); | |||
| transform: translateX(0); | |||
| } | |||
| } | |||
| @-webkit-keyframes slide-out-right { | |||
| 0% { | |||
| from { | |||
| -webkit-transform: translateX(0); | |||
| transform: translateX(0); | |||
| opacity: 1; | |||
| } | |||
| 100% { | |||
| overflow: hidden; | |||
| width: 100%; | |||
| 99% { | |||
| opacity: 0 !important; | |||
| width: 100% !important; | |||
| height: 100% !important; | |||
| } | |||
| to { | |||
| height: 0px !important; | |||
| width: 0px; | |||
| opacity: 0 !important; | |||
| display: none !important; | |||
| visibility: hidden !important; | |||
| -webkit-transform: translateX(1000px); | |||
| transform: translateX(1000px); | |||
| overflow: hidden; | |||
| opacity: 0; | |||
| width: 0px; | |||
| height: 0px; | |||
| } | |||
| } | |||
| @keyframes slide-out-right { | |||
| 0% { | |||
| from { | |||
| -webkit-transform: translateX(0); | |||
| transform: translateX(0); | |||
| opacity: 1; | |||
| } | |||
| 100% { | |||
| overflow: hidden; | |||
| width: 100%; | |||
| 99% { | |||
| opacity: 0 !important; | |||
| width: 100% !important; | |||
| height: 100% !important; | |||
| } | |||
| to { | |||
| height: 0px; | |||
| width: 0px; | |||
| opacity: 0 !important; | |||
| display: none !important; | |||
| visibility: hidden !important; | |||
| -webkit-transform: translateX(1000px); | |||
| transform: translateX(1000px); | |||
| overflow: hidden; | |||
| opacity: 0; | |||
| width: 0px; | |||
| height: 0px; | |||
| } | |||
| } | |||
| @-webkit-keyframes slide-out-left { | |||
| 0% { | |||
| from { | |||
| -webkit-transform: translateX(0); | |||
| transform: translateX(0); | |||
| opacity: 1; | |||
| } | |||
| 100% { | |||
| overflow: hidden; | |||
| width: 100%; | |||
| 99% { | |||
| opacity: 0 !important; | |||
| width: 100% !important; | |||
| height: 100% !important; | |||
| } | |||
| to { | |||
| height: 0px; | |||
| width: 0px; | |||
| opacity: 0 !important; | |||
| display: none !important; | |||
| visibility: hidden !important; | |||
| -webkit-transform: translateX(-1000px); | |||
| transform: translateX(-1000px); | |||
| overflow: hidden; | |||
| opacity: 0; | |||
| width: 0px; | |||
| height: 0px; | |||
| } | |||
| } | |||
| @keyframes slide-out-left { | |||
| 0% { | |||
| from { | |||
| -webkit-transform: translateX(0); | |||
| transform: translateX(0); | |||
| opacity: 1; | |||
| } | |||
| 100% { | |||
| overflow: hidden; | |||
| width: 100%; | |||
| 99% { | |||
| opacity: 0 !important; | |||
| width: 100% !important; | |||
| height: 100% !important; | |||
| } | |||
| to { | |||
| height: 0px; | |||
| width: 0px; | |||
| opacity: 0 !important; | |||
| display: none !important; | |||
| visibility: hidden !important; | |||
| -webkit-transform: translateX(-1000px); | |||
| transform: translateX(-1000px); | |||
| opacity: 0; | |||
| width: 0px; | |||
| height: 0px; | |||
| } | |||
| } | |||
| @@ -114,32 +131,30 @@ | |||
| } | |||
| .slide-in-left { | |||
| visibility: visible; | |||
| -webkit-animation: slide-in-left 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both; | |||
| animation: slide-in-left 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both; | |||
| -webkit-animation: slide-in-left 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards; | |||
| animation: slide-in-left 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards; | |||
| } | |||
| .slide-in-right { | |||
| visibility: visible; | |||
| -webkit-animation: slide-in-right 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both; | |||
| animation: slide-in-right 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both; | |||
| -webkit-animation: slide-in-right 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards; | |||
| animation: slide-in-right 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards; | |||
| } | |||
| .slide-out-right { | |||
| -webkit-animation: slide-out-right 0.5s cubic-bezier(0.55, 0.085, 0.68, 0.53) both; | |||
| animation: slide-out-right 0.5s cubic-bezier(0.55, 0.085, 0.68, 0.53) both; | |||
| -webkit-animation: slide-out-right 0.5s cubic-bezier(0.55, 0.085, 0.68, 0.53) forwards; | |||
| animation: slide-out-right 0.5s cubic-bezier(0.55, 0.085, 0.68, 0.53) forwards; | |||
| } | |||
| .slide-out-left { | |||
| -webkit-animation: slide-out-left 0.5s cubic-bezier(0.55, 0.085, 0.68, 0.53) both; | |||
| animation: slide-out-left 0.5s cubic-bezier(0.55, 0.085, 0.68, 0.53) both; | |||
| -webkit-animation: slide-out-left 0.5s cubic-bezier(0.55, 0.085, 0.68, 0.53) forwards; | |||
| animation: slide-out-left 0.5s cubic-bezier(0.55, 0.085, 0.68, 0.53) forwards; | |||
| } | |||
| .inactive { | |||
| display: none; | |||
| display: none !important; | |||
| visibility: hidden !important !important !important; | |||
| } | |||
| .pane { | |||
| width: 100%; | |||
| } | |||
| @@ -7,19 +7,7 @@ $border-radius: 12.5px; | |||
| padding: 1em; | |||
| } | |||
| .title { | |||
| justify-self: flex-start; | |||
| align-items: self-start; | |||
| } | |||
| .tab-title:active, | |||
| .active { | |||
| opacity: 1; | |||
| } | |||
| .tab-title:hover { | |||
| opacity: 0.8; | |||
| } | |||
| @@ -34,18 +22,37 @@ $border-radius: 12.5px; | |||
| .tab-container { | |||
| border-radius: $border-radius; | |||
| background: white; | |||
| width: 100%; | |||
| min-height: 60rem; | |||
| } | |||
| .header-icon { | |||
| padding: 1em; | |||
| } | |||
| .tab-title:active, | |||
| .active { | |||
| opacity: 1; | |||
| } | |||
| .tab-title:hover { | |||
| opacity: 0.8; | |||
| } | |||
| .header { | |||
| justify-content: space-between; | |||
| align-items: spac; | |||
| height: 3em; | |||
| flex-direction: row nowrap; | |||
| flex-direction: row; | |||
| font-size: $header-font-size; | |||
| color: white; | |||
| background: linear-gradient(48deg, $detail-color, $secondary-color, $primary-color); | |||
| } | |||
| @media(max-width: 600px) { | |||
| .header { | |||
| font-size: $header-font-size / 2; | |||
| } | |||
| } | |||
| @@ -3,7 +3,7 @@ export enum Category { | |||
| 'Entertainment' = 'entertainment', | |||
| 'General' = 'general', | |||
| 'Health' = 'health', | |||
| 'Scince' = 'science', | |||
| 'Science' = 'science', | |||
| 'Sports' = 'sports', | |||
| 'Technology' = 'technology', | |||
| } | |||
| @@ -1,5 +1,29 @@ | |||
| <div class="flex-container wrap"> | |||
| <div class="title flex-container"> | |||
| <p>News</p> | |||
| </div> | |||
| <div class="flex-container filter-bar"> | |||
| <div class="filter"> | |||
| <label for="search">Search: </label> | |||
| <input | |||
| (change)="search()" | |||
| name="search" | |||
| id="search" | |||
| [(ngModel)]="searchDto.q" | |||
| /> | |||
| </div> | |||
| </div> | |||
| <div class="flex-container wrap" *ngIf="news?.length; else notingFound"> | |||
| <div class="flex-item" *ngFor="let article of news"> | |||
| <app-news-teaser [article]="article"></app-news-teaser> | |||
| </div> | |||
| </div> | |||
| <ng-template #notingFound> | |||
| <div class="flex-container not-found"> | |||
| noting here | |||
| </div> | |||
| </ng-template> | |||
| @@ -0,0 +1,39 @@ | |||
| @import "../../../variables.scss"; | |||
| .filter-bar { | |||
| height: 5em; | |||
| margin: 2em; | |||
| display: flex; | |||
| flex-flow: row; | |||
| justify-content: space-evenly; | |||
| align-items: center; | |||
| border: 1px solid $border-color; | |||
| } | |||
| .filter { | |||
| height: 2em; | |||
| } | |||
| .title { | |||
| padding-top: 1em; | |||
| } | |||
| .flag { | |||
| height: 1em; | |||
| padding-left: 0.5em; | |||
| align-self: center; | |||
| } | |||
| .not-found { | |||
| width: auto; | |||
| height: 100%; | |||
| padding: 5em; | |||
| } | |||
| @media (max-width: 600px) { | |||
| .filter-bar { | |||
| flex-flow: column; | |||
| justify-content: center; | |||
| } | |||
| } | |||
| @@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core'; | |||
| import { NewsService } from '../../service/news.service'; | |||
| import { Article } from '../../models/model/article'; | |||
| import { apiKey } from '../../../environments/.api-key'; | |||
| import { NewsSearchDto } from '../../models/dto/news-search.dto'; | |||
| @Component({ | |||
| selector: 'app-all-news-dashboard', | |||
| @@ -10,15 +11,18 @@ import { apiKey } from '../../../environments/.api-key'; | |||
| }) | |||
| export class AllNewsDashboardComponent implements OnInit { | |||
| searchDto: NewsSearchDto = {apiKey}; | |||
| news: Article[]; | |||
| constructor(protected newsService: NewsService) { } | |||
| search(): void { | |||
| this.newsService.searchAllNews(this.searchDto).subscribe(response => { | |||
| this.news = response.articles; | |||
| }); | |||
| } | |||
| ngOnInit(): void { | |||
| // this.newsService.searchAllNews({ | |||
| // apiKey | |||
| // }).subscribe(response => { | |||
| // this.news = response.articles; | |||
| // }); | |||
| } | |||
| @@ -1,8 +1,8 @@ | |||
| <app-tabs> | |||
| <app-tab style="width: auto" title="Top News"> | |||
| <app-tab title="Top News"> | |||
| <app-top-news-dashboard></app-top-news-dashboard> | |||
| </app-tab> | |||
| <app-tab style="width: auto" title="All News"> | |||
| <app-tab title="All News"> | |||
| <app-all-news-dashboard></app-all-news-dashboard> | |||
| </app-tab> | |||
| </app-tabs> | |||
| @@ -1,9 +1,10 @@ | |||
| <div | |||
| (click)="open()" | |||
| class="teaser" | |||
| *ngIf="article.urlToImage && article.content" | |||
| *ngIf="article.urlToImage && article.description && article.url" | |||
| > | |||
| <div class="teaser-header"> | |||
| <div class="date" >{{ article.publishedAt | date:"dd-MM-yyyy" }}</div> | |||
| <div class="teaser-title">{{ article.title }}</div> | |||
| <div class="teaser-img"> | |||
| <img | |||
| @@ -13,7 +14,9 @@ | |||
| /> | |||
| </div> | |||
| </div> | |||
| <div class="teaser-content" *ngIf="article.description"> | |||
| {{ article.description }} ... <a [href]="article.url"> Read</a> | |||
| <div class="teaser-content"> | |||
| <ng-container *ngIf="article.description"> | |||
| {{ article.description }} ... <a [href]="article.url"> Read</a> | |||
| </ng-container> | |||
| </div> | |||
| </div> | |||
| @@ -4,8 +4,8 @@ $teaser-border-radius: 12.5px; | |||
| $teaser-background: linear-gradient(48deg, rgb(223, 217, 217), white); | |||
| .teaser-header { | |||
| min-height: 10em; | |||
| flex-direction: column; | |||
| max-width: 40em; | |||
| > div.teaser-img { | |||
| border-top-left-radius: $teaser-border-radius; | |||
| border-top-right-radius: $teaser-border-radius; | |||
| @@ -14,18 +14,28 @@ $teaser-background: linear-gradient(48deg, rgb(223, 217, 217), white); | |||
| justify-content: center; | |||
| align-items: center; | |||
| > img { | |||
| padding: 5px; | |||
| max-width: 40em; | |||
| max-height: 20em; | |||
| max-width: 100%; | |||
| height: auto; | |||
| } | |||
| } | |||
| > div.teaser-title { | |||
| padding: 2em; | |||
| background: transparent; | |||
| max-width: 40em; | |||
| display: flex; | |||
| justify-content: center; | |||
| align-items: center; | |||
| flex-direction: column; | |||
| padding: 1em; | |||
| text-align: center; | |||
| font-size: $header-font-size; | |||
| } | |||
| > div.date { | |||
| display: flex; | |||
| justify-content: center; | |||
| align-items: center; | |||
| padding-bottom: 0.5rem; | |||
| padding-top: 1rem; | |||
| flex-direction: column; | |||
| text-align: center; | |||
| } | |||
| > div.teaser-title::after { | |||
| content: ""; | |||
| background-color: $detail-color; | |||
| @@ -39,8 +49,8 @@ $teaser-background: linear-gradient(48deg, rgb(223, 217, 217), white); | |||
| .teaser { | |||
| cursor: pointer; | |||
| border: 1px solid $border-color; | |||
| width: 45em; | |||
| min-height: 20em; | |||
| max-width: 30em; | |||
| min-height: max-content; | |||
| border-radius: $teaser-border-radius; | |||
| } | |||
| @@ -59,14 +69,15 @@ $teaser-background: linear-gradient(48deg, rgb(223, 217, 217), white); | |||
| animation: hover 0.3s cubic-bezier(0.39, 0.575, 0.565, 1) both; | |||
| } | |||
| .teaser-content { | |||
| background: $teaser-background; | |||
| border-bottom-left-radius: $teaser-border-radius; | |||
| border-bottom-right-radius: $teaser-border-radius; | |||
| min-width: 10em; | |||
| padding: 5px; | |||
| display: flex; | |||
| justify-content: center; | |||
| align-items: center; | |||
| flex-direction: column; | |||
| padding: 1em; | |||
| } | |||
| .teaser-footer { | |||
| @@ -84,3 +95,9 @@ a { | |||
| color: $detail-color; | |||
| text-decoration: none; | |||
| } | |||
| @media (max-width: 600px) { | |||
| div.teaser-title { | |||
| font-size: $header-font-size / 2 !important; | |||
| } | |||
| } | |||
| @@ -15,8 +15,8 @@ | |||
| } | |||
| .title { | |||
| padding-top: 1em; | |||
| background: transparent; | |||
| font-size: $header-font-size; | |||
| } | |||
| .flag { | |||
| @@ -29,3 +29,10 @@ | |||
| width: 160em; | |||
| height: 10em; | |||
| } | |||
| @media (max-width: 600px) { | |||
| .filter-bar { | |||
| flex-flow: column; | |||
| justify-content: center; | |||
| } | |||
| } | |||
| @@ -13,7 +13,7 @@ import { Category } from 'src/app/models/enum/category'; | |||
| }) | |||
| export class TopNewsDashboardComponent implements OnInit { | |||
| news: Article[]; | |||
| searchDto: TopHeadlineSearchDto = { apiKey }; | |||
| searchDto: TopHeadlineSearchDto = { apiKey, }; | |||
| selectedCountry: { key: string, value: CountryCode }; | |||
| selectedCategory: { key: string, value: Category }; | |||
| CountryCodes = CountryCode; | |||
| @@ -64,3 +64,16 @@ html { | |||
| height: 100%; | |||
| margin: 0px; | |||
| } | |||
| .title { | |||
| font-size: $header-font-size; | |||
| } | |||
| @media (max-width: 600px) { | |||
| .title { | |||
| font-size: $header-font-size / 2; | |||
| } | |||
| } | |||
| @@ -1,4 +1,3 @@ | |||
| $base-color: transparent; | |||
| $primary-color: #2f85f6; | |||
| $secondary-color: #8c3cee; | |||
| @@ -10,11 +9,8 @@ $text-primary: white; | |||
| $border-color: #d8d8d8; | |||
| $footer-height: 1.2em; | |||
| $default-font-size: 15px; | |||
| $header-font-size: 25px; | |||