design movie hero banner & category
This commit is contained in:
parent
7bda7ca5d2
commit
3ab7614e7e
11 changed files with 263 additions and 3 deletions
3
frontend/.gitignore
vendored
3
frontend/.gitignore
vendored
|
|
@ -40,3 +40,6 @@ testem.log
|
||||||
# System files
|
# System files
|
||||||
.DS_Store
|
.DS_Store
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
|
||||||
|
# Movies
|
||||||
|
src/assets/movies/*
|
||||||
|
|
@ -1,3 +1,8 @@
|
||||||
<section>
|
<section>
|
||||||
<app-header [browse]="true"></app-header>
|
<app-header [browse]="true"></app-header>
|
||||||
|
<app-hero-banner [currentMovie]="currentMovie"></app-hero-banner>
|
||||||
|
<app-categories
|
||||||
|
[movies]="movies"
|
||||||
|
(currentMovieId)="currentMovieId($event)"
|
||||||
|
></app-categories>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,43 @@
|
||||||
import { Component } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { HeaderComponent } from '../../../shared/components/header/header.component';
|
import { HeaderComponent } from '../../../shared/components/header/header.component';
|
||||||
|
import { HeroBannerComponent } from './hero-banner/hero-banner.component';
|
||||||
|
import { CategoriesComponent } from './categories/categories.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-browse',
|
selector: 'app-browse',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [HeaderComponent],
|
imports: [HeaderComponent, HeroBannerComponent, CategoriesComponent],
|
||||||
templateUrl: './browse.component.html',
|
templateUrl: './browse.component.html',
|
||||||
styleUrl: './browse.component.scss',
|
styleUrl: './browse.component.scss',
|
||||||
})
|
})
|
||||||
export class BrowseComponent {}
|
export class BrowseComponent implements OnInit {
|
||||||
|
movies = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
title: 'Our Galaxy',
|
||||||
|
description:
|
||||||
|
'Experience the fascinating journey through the infinite expanse of our galaxy. "Our Galaxy" offers a detailed insight into the breathtaking structures, stars and planets of our cosmic home. Through stunning visual effects and comprehensive explanations, this documentary guides viewers through the mysteries of the universe and reveals the beauty and complexity of outer space. Perfect for astronomy lovers and the curious who want to learn more about the wonders of the universe',
|
||||||
|
category: 'documentation',
|
||||||
|
imgPath: 'galaxy.png',
|
||||||
|
videoPath: 'galaxy.mp4',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
currentMovie: any[] = [];
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.currentMovie.length === 0 ? this.loadRandomMovie() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadRandomMovie(): void {
|
||||||
|
const randomIndex = Math.floor(Math.random() * this.movies.length);
|
||||||
|
this.currentMovie = [this.movies[randomIndex]];
|
||||||
|
}
|
||||||
|
|
||||||
|
currentMovieId(movieId: number) {
|
||||||
|
let index = this.movies.findIndex((movie) => movie.id === movieId);
|
||||||
|
if (index !== -1) {
|
||||||
|
this.currentMovie = [];
|
||||||
|
this.currentMovie.push(this.movies[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
<section class="hide-scrollbar">
|
||||||
|
<div class="category">
|
||||||
|
<p>New Releases</p>
|
||||||
|
@for (movie of movies; track movie) {
|
||||||
|
<div class="movie" (click)="openCurrentMovie(movie.id)">
|
||||||
|
<img
|
||||||
|
src="./../../../../../assets/movies/banner/{{ movie.imgPath }}"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div class="category">
|
||||||
|
<p>Continue Watching</p>
|
||||||
|
</div>
|
||||||
|
<div class="category">
|
||||||
|
<p>Action & Adventure</p>
|
||||||
|
</div>
|
||||||
|
<div class="category">
|
||||||
|
<p>Science Fiction & Fantasy</p>
|
||||||
|
</div>
|
||||||
|
<div class="category">
|
||||||
|
<p>Drama & Romance</p>
|
||||||
|
</div>
|
||||||
|
<div class="category">
|
||||||
|
<p>All Other Categories</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
@import "./../../../../../assets/style/colors.scss";
|
||||||
|
|
||||||
|
section {
|
||||||
|
height: 60%;
|
||||||
|
padding: 0 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category {
|
||||||
|
height: 165px;
|
||||||
|
p {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie {
|
||||||
|
width: 213px;
|
||||||
|
height: 120px;
|
||||||
|
padding: 6px 6px 6px 0;
|
||||||
|
img {
|
||||||
|
width: 213px;
|
||||||
|
height: 120px;
|
||||||
|
transition: scale 300ms ease-in-out;
|
||||||
|
border: 2px solid rgba($black, 0);
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover {
|
||||||
|
scale: 1.02;
|
||||||
|
border: 2px solid $blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide scrollbar
|
||||||
|
|
||||||
|
.hide-scrollbar {
|
||||||
|
overflow: scroll;
|
||||||
|
height: 60%;
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hide-scrollbar::-webkit-scrollbar {
|
||||||
|
width: 0px;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { CategoriesComponent } from './categories.component';
|
||||||
|
|
||||||
|
describe('CategoriesComponent', () => {
|
||||||
|
let component: CategoriesComponent;
|
||||||
|
let fixture: ComponentFixture<CategoriesComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [CategoriesComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(CategoriesComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-categories',
|
||||||
|
standalone: true,
|
||||||
|
imports: [],
|
||||||
|
templateUrl: './categories.component.html',
|
||||||
|
styleUrl: './categories.component.scss',
|
||||||
|
})
|
||||||
|
export class CategoriesComponent {
|
||||||
|
@Input() movies: any[] = [];
|
||||||
|
@Output() currentMovieId = new EventEmitter<number>();
|
||||||
|
|
||||||
|
openCurrentMovie(movieId: number) {
|
||||||
|
this.currentMovieId.emit(movieId);
|
||||||
|
}
|
||||||
|
|
||||||
|
get documentaryMovies() {
|
||||||
|
return this.movies.filter((movie) => movie.category === 'documentary');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
<section
|
||||||
|
class="movie-banner"
|
||||||
|
[style.backgroundImage]="'url(' + getImagePath() + ')'"
|
||||||
|
>
|
||||||
|
@if (currentMovie.length > 0) {
|
||||||
|
<div class="content">
|
||||||
|
<div class="title">{{ currentMovie[0].title }}</div>
|
||||||
|
<div class="description">
|
||||||
|
{{ currentMovie[0].description }}
|
||||||
|
</div>
|
||||||
|
<app-btn-large [value]="'Play'"></app-btn-large>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</section>
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
@import "./../../../../../assets/style/colors.scss";
|
||||||
|
|
||||||
|
section {
|
||||||
|
height: 40%;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
img {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
position: absolute;
|
||||||
|
width: 40%;
|
||||||
|
height: 40%;
|
||||||
|
top: 140px;
|
||||||
|
left: 96px;
|
||||||
|
gap: 32px;
|
||||||
|
opacity: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 5vw;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
font-size: 1.2vw;
|
||||||
|
font-weight: 400;
|
||||||
|
overflow: scroll;
|
||||||
|
height: 40%;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
scrollbar-width: none;
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
width: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-banner {
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { HeroBannerComponent } from './hero-banner.component';
|
||||||
|
|
||||||
|
describe('HeroBannerComponent', () => {
|
||||||
|
let component: HeroBannerComponent;
|
||||||
|
let fixture: ComponentFixture<HeroBannerComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [HeroBannerComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(HeroBannerComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { Component, Input } from '@angular/core';
|
||||||
|
import { BtnLargeComponent } from '../../../../shared/components/btn-large/btn-large.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-hero-banner',
|
||||||
|
standalone: true,
|
||||||
|
imports: [CommonModule, BtnLargeComponent],
|
||||||
|
templateUrl: './hero-banner.component.html',
|
||||||
|
styleUrl: './hero-banner.component.scss',
|
||||||
|
})
|
||||||
|
export class HeroBannerComponent {
|
||||||
|
@Input() currentMovie: any[] = [];
|
||||||
|
|
||||||
|
getImagePath(): string {
|
||||||
|
return `./../../../../../assets/movies/banner/${this.currentMovie[0]?.imgPath}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue