Browse Source

Article Details page transition and UI

master
kj1352 4 years ago
parent
commit
b68f64bcf1
4 changed files with 462 additions and 40 deletions
  1. +75
    -25
      src/app/home/home.page.html
  2. +317
    -11
      src/app/home/home.page.scss
  3. +53
    -4
      src/app/home/home.page.ts
  4. +17
    -0
      src/global.scss

+ 75
- 25
src/app/home/home.page.html View File

@@ -1,26 +1,43 @@
<ion-content>
<h2 class="main-header"> Home </h2>
<figure class="theme-bg-image">
<img src="assets/home-team/KXIP-lion-white.svg">
</figure>

<div class="heading-holder">
<h2 class="main-header"> Home </h2>
<section class="segments">
<button [ngClass]="{'active' : selectedTab === 'news'}"
(click)="selectedTab = 'news'"> News ({{ newsData.length }}) </button>
<button [ngClass]="{'active' : selectedTab === 'videos'}"
(click)="selectedTab = 'videos'"> Videos </button>
</section>
<section class="segments">
<button [ngClass]="{'active' : selectedTab === 'news'}"
(click)="selectedTab = 'news'"> News ({{ newsData.length }}) </button>
<button [ngClass]="{'active' : selectedTab === 'videos'}"
(click)="selectedTab = 'videos'"> Videos </button>
</section>
</div>

<button (click)="closeArticle()"
class="close-article-button"
[ngClass]="{'active' : selectedArticle !== null }">
<ion-icon name="close"></ion-icon>
</button>

<ion-slides [options]="slideOpts">
<ion-slide *ngFor="let news of newsData">
<ion-slides [options]="slideOpts" *ngIf="selectedTab === 'news'"
[ngClass]="{'active' : selectedArticle !== null}">

<ion-slide *ngFor="let news of newsData; let i = index">
<div class="image-holder">
<figure>
<img [src]="news.image">
</figure>

<button *ngIf="news.type === 'VIDEO'">
<button
[ngClass]="{'active' : selectedArticle !== null}"
*ngIf="news.type === 'VIDEO'">
<ion-icon name="play"></ion-icon>
</button>

<button *ngIf="news.type === 'ARTICLE'">
<button
[ngClass]="{'hide' : selectedArticle !== null}"
*ngIf="news.type === 'ARTICLE'">
<ion-icon name="newspaper"></ion-icon>
</button>
</div>
@@ -28,30 +45,63 @@
<section class="content">
<h4> {{ news.heading }} </h4>

<p>
<div class="details">
{{ news.description }}
</p>
</div>
</section>


<section class="comments" *ngIf="selectedArticle !== null">
<header> Comments </header>
<ul>
<li *ngFor="let comment of news.comments">
<p> {{ comment.comment }} <label> - {{ comment.user }} </label> </p>

<button (click)="comment.isLiked = !comment.isLiked"
[ngClass]="{'active' : comment.isLiked}">
<ion-icon *ngIf="!comment.isLiked" name="heart-outline"></ion-icon>
<ion-icon *ngIf="comment.isLiked" name="heart"></ion-icon>
<span> {{ comment.isLiked ? comment.likes + 1 : comment.likes }} </span>
</button>
</li>
<div class="input-holder" id="comment-input">
<input type="text" placeholder="Type your comment" [(ngModel)]="myComment">
<button (click)="postComment()"> <ion-icon name="send"></ion-icon> </button>
</div>
</ul>
</section>

<section class="action-buttons">
<section class="shortcuts">
<button>
<ion-icon name="share-social-outline"></ion-icon>
</button>

<button (click)="news.isLiked = !news.isLiked"
<button class="wide-button" (click)="news.isLiked = !news.isLiked"
[ngClass]="{'active' : news.isLiked}">
<ion-icon *ngIf="!news.isLiked" name="heart-outline"></ion-icon>
<ion-icon *ngIf="news.isLiked" name="heart"></ion-icon>
<span> {{ news.isLiked ? news.likes + 1 : news.likes }} </span>
</button>
</button>

<button>
<ion-icon name="share-social-outline"></ion-icon>
</button>
</section>

<button class="read-more">
<span *ngIf="news.type === 'ARTICLE'"> Read More </span>
<span *ngIf="news.type === 'VIDEO'"> Watch </span>
<ion-icon name="chevron-forward-outline"></ion-icon> </button>
<section class="shortcuts" *ngIf="selectedArticle !== null">
<button (click)="news.isBookmarked = !news.isBookmarked"
[ngClass]="{'active' : news.isBookmarked}">
<ion-icon *ngIf="!news.isBookmarked" name="bookmark-outline"></ion-icon>
<ion-icon *ngIf="news.isBookmarked" name="bookmark"></ion-icon>
</button>

<button class="wide-button" (click)="scrollToAddComment()">
<ion-icon name="chatbubble-outline"></ion-icon>
<span> {{ news.comments.length }} </span>
</button>
</section>

<button class="read-more" (click)="expandArticle(i)">
<span> More </span>
<ion-icon name="chevron-forward-outline"></ion-icon>
</button>
</section>

</ion-slide>


+ 317
- 11
src/app/home/home.page.scss View File

@@ -1,5 +1,12 @@
ion-content {
--background: var(--brand-black);
--background: var(--brand-black);
}

.heading-holder {
position: fixed;
top: 0;
left: 0;
width: 100%;
}

.main-header {
@@ -48,9 +55,126 @@ ion-content {
}
}

.close-article-button {
width: 40px;
height: 40px;
position: fixed;
top: 10px;
right: 10px;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(#ffff, 0.5);
border-radius: 50%;
z-index: 3;
opacity: 0;
transform: translateY(10px);
pointer-events: none;
transition: opacity 0.3s, transform 0.3s;

&.active {
opacity: 1;
transition-delay: 1s;
transform: translateY(0px);
pointer-events: all;
}

ion-icon {
color: white;
font-size: 20px;
}
}

ion-slides {
margin: 12% 0%;
margin-top: 40%;
height: calc(100vh - 40%);
position: relative;
left: 0;
top: 0;
transition: transform 0.5s, height 0.3s, margin 0.3s, width 0.3s;
z-index: 1;

&.active {
margin: 0px;
width: 100%;
transform: translate(0, 0%);
height: calc(100vh - 56px);

ion-slide {
background-color: white;
border-radius: 0px;
overflow: auto;

.content {
width: 90%;
height: auto;
background-color: white;
transform: translateY(-30px);
position: relative;
border-radius: 10px;
transition-delay: 0.3s;
overflow: auto;
border-width: 0px;
box-shadow: 0px 0px 15px rgba(var(--light-grey-rgb), 0.3);

h4, .details {
opacity: 0;
animation: showUpContent 0.3s forwards;
animation-delay: 0.3s;
}
}

.action-buttons {
width: 90%;
background-color: white;
border-radius: 10px;
position: sticky;
position: -webkit-sticky;
bottom: 0;
z-index: 2;
box-shadow: 0px 0px 15px rgba(var(--light-grey-rgb), 0.3);
justify-content: center;
height: 60px;

.shortcuts {
width: 50%;

button {
background-color: rgba(var(--light-grey-rgb), 0.1);
margin: 0 auto;
width: 40px;
height: 40px;
&.wide-button {
width: auto;
padding: 0 10px;
}
}
}

.read-more {
display: none;
}
}
.image-holder figure {
filter: brightness(30%);
}
}
}
@keyframes showUpContent {
0% {
opacity: 0;
transform: translateY(20px);
-webkit-line-clamp: 4;
}
100% {
opacity: 1;
-webkit-line-clamp: unset;
transform: translateY(0px);
}
}

ion-slide {
display: block;
@@ -59,10 +183,13 @@ ion-slides {
text-align: left;
align-self: start;
height: 100%;
transition: width 0.5s, transform 0.3s, margin 0.3s;
}

.image-holder {
position: relative;
position: sticky;
position: -webkit-sticky;
top: 0;
height: 40%;
overflow: hidden;

@@ -77,10 +204,41 @@ ion-slides {
justify-content: center;
background-color: rgba(#ffff, 0.5);
border-radius: 50%;
transition: transform 0.3s, background-color 0.3s, opacity 0.3s;

&.hide {
opacity: 0;
pointer-events: none;
}

&.active {
transform: translate(calc(-50vw + 40px), -15vh);
animation: ripple 1s infinite;
background-color: rgba(var(--brand-red-rgb), 0.5);

ion-icon {
color: white;
}
}

@keyframes ripple {
0% {
box-shadow: 0px 0px 0px var(--brand-red);
}
50% {
box-shadow: 0px 0px 5px var(--brand-red);
}

100% {
box-shadow: 0px 0px 0px var(--brand-red);
}
}

ion-icon {
color: white;
font-size: 20px;
transition: color 0.3s;
}
}

@@ -90,6 +248,7 @@ ion-slides {
width: 100%;
height: 100%;
filter: brightness(60%);
transition: filter 0.3s;

img {
height: 100%;
@@ -102,11 +261,18 @@ ion-slides {

.content {
background-color: white;
padding: 5%;
padding: 0px 5% 5% 5%;
width: 100%;
margin: 0 auto;
height: calc(60% - 50px);
overflow: hidden;
margin-top: -1px;
border-bottom: 1px solid rgba(var(--light-grey-rgb), 0.8);
border-radius: 0px;
transform: translateY(0px);
box-shadow: 0px 0px 0px var(--light-grey);
transition: border-radius 0.3s, transform 0.3s, width 0.3s, margin 0.3s, box-shadow 0.3s;
border-bottom: 1px solid rgba(var(--light-grey-rgb), 0.3);
z-index: 2;
}

h4 {
@@ -114,11 +280,18 @@ ion-slides {
margin: 0px;
line-height: 1.5;
font-weight: 500;
color: var(--brand-black);
color: var(--brand-black);
transition: opacity 0.1s;
background-color: white;
position: sticky;
position: -webkit-sticky;
top: 1px;
z-index: 1;
padding: 10px 0;
}
p {
margin: 5px 0px 0px 0px;
.details {
margin: 0px;
font-size: 0.9rem;
line-height: 1.5;
font-weight: 400;
@@ -127,6 +300,7 @@ ion-slides {
-webkit-box-orient: vertical;
color: var(--light-grey);
overflow: hidden;
transition: opacity 0.1s;
}

.action-buttons {
@@ -136,16 +310,31 @@ ion-slides {
width: 100%;
height: 50px;
margin-top: -1px;
padding: 0 3%;
padding: 0 3%;
position: relative;
box-shadow: 0px 0px 0px var(--light-grey);
transition: border-radius 0.3s, transform 0.3s, width 0.3s, margin 0.3s, box-shadow 0.3s;
z-index: 1;
margin: 0 auto 20px;

.shortcuts {
display: flex;
align-items: stretch;
align-items: center;
height: 100%;

button {
background-color: transparent;
background-color: #f3f3f3;
margin-right: 5px;
width: 30px;
height: 30px;
border-radius: 50%;

&.wide-button {
width: auto;
border-radius: 5px;
padding: 0 10px;
}

&.active {
ion-icon, span {
@@ -153,6 +342,14 @@ ion-slides {
}
}

// &.bookmark-button {
// &.active {
// ion-icon, span {
// color: var(--light-grey);
// }
// }
// }

span {
vertical-align: middle;
color: var(--light-grey);
@@ -181,4 +378,113 @@ ion-slides {
}
}

.comments {
background-color: white;
width: 90%;
position: relative;
box-shadow: 0px 0px 0px var(--light-grey);
z-index: 1;
margin: 0px auto 20px;
border-radius: 10px;
box-shadow: 0px 0px 15px rgba(var(--light-grey-rgb), 0.3);
border-radius: 10px;
overflow: hidden;
header {
font-size: 1.1rem;
margin: 0px;
line-height: 1.5;
font-weight: 500;
color: var(--brand-black);
transition: opacity 0.1s;
background-color: white;
padding: 10px 5%;
}

ul {
list-style: none;
padding: 0;
margin: 0;

li {
padding: 5px 5% 10px;
border-top: 1px solid rgba(var(--light-grey-rgb), 0.3);
line-height: 1.5;
}

label {
font-size: 1rem;
font-weight: 500;
letter-spacing: 1px;
color: rgba(var(--brand-red-rgb), 0.8);
}

p {
margin: 3px 0;
font-size: 1rem;
font-weight: 400;
color: var(--light-grey);
}

button {
background-color: #f3f3f3;
margin-right: 5px;
height: 30px;
width: auto;
border-radius: 5px;
padding: 0 5px;

span {
vertical-align: middle;
color: var(--light-grey);
}
ion-icon {
vertical-align: middle;
color: var(--brand-black);
font-size: 1rem;
}

&.active {
ion-icon, span {
color: var(--brand-red);
}
}
}

.input-holder {
display: flex;
width: 100%;
height: 70px;
align-items: center;

input {
width: calc(100% - 80px);
margin: 0 auto;
border: 1px solid rgba(var(--light-grey-rgb), 0.3);
border-radius: 30px;
font-size: 14px;
color: var(--brand-black);
font-weight: 500;
height: 40px;
padding: 0 15px;
}

button {
width: 40px;
height: 40px;
background-color: var(--brand-red);
margin: 0 auto;
border-radius: 50%;

ion-icon {
color: white;
font-size: 16px;
}
}
}
}
}

}

+ 53
- 4
src/app/home/home.page.ts View File

@@ -7,6 +7,8 @@ import { Component, OnInit } from '@angular/core';
})
export class HomePage implements OnInit {
selectedTab: string = 'news';
selectedArticle: number = null;
myComment: string = '';

slideOpts = { };

@@ -22,7 +24,8 @@ export class HomePage implements OnInit {
comments: Array<{
user: string,
comment: string,
likes: number
likes: number,
isLiked: boolean
}>,
}> = [];

@@ -34,7 +37,14 @@ export class HomePage implements OnInit {
id: 1,
image: 'https://s3.india.com/wp-content/uploads/2020/10/Mayank-Agarwal-celebrates-Kings-XI-Punjabs-win-over-Mumbai-Indians-in-match-37-of-Dream11-IPL-2020-in-Dubai%C2%A9KXIP-Twitter.jpg',
heading: 'KXIP beat MI by 3 Wickets',
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iste ab qui, incidunt illo dolore laboriosam sapiente deserunt officiis ullam. Explicabo accusantium quia tempore totam repellat amet debitis adipisci deserunt iste.',
description: `Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iste ab qui, incidunt illo dolore laboriosam sapiente deserunt officiis ullam.
Explicabo accusantium quia tempore totam repellat amet debitis adipisci deserunt iste.

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iste ab qui, incidunt illo dolore laboriosam sapiente deserunt officiis u
santium quia tempore totam repellat amet debitis adipisci deserunt iste.
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iste ab qui, incidunt illo dolore laboriosam sapiente deserunt officiis u
santium quia tempore totam repellat amet debitis adipisci deserunt iste.`,
type: 'VIDEO',
likes: 10,
isLiked: false,
@@ -43,16 +53,18 @@ export class HomePage implements OnInit {
user: 'kxipFan',
comment: 'Yay!',
likes: 2,
isLiked: true,
}, {
user: 'SehwagFan',
comment: 'finally!',
likes: 5,
isLiked: false,
}]
}, {
id: 2,
image: 'https://www.ak4tsay1.com/wp-content/uploads/2020/02/Kings-XI-Punjab-KXIP-Strengths-and-Weakness-for-IPL-2020-800x445.jpg',
heading: 'KL Rahul scores fastest 100',
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iste ab qui, incidunt illo dolore laboriosam sapiente deserunt officiis ullam. Explicabo accusantium quia tempore totam repellat amet debitis adipisci deserunt iste.',
description: `Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iste ab qui, incidunt illo dolore laboriosam sapiente deserunt officiis ullam. Explicabo accusantium quia tempore totam repellat amet debitis adipisci deserunt iste.`,
type: 'ARTICLE',
isLiked: false,
isBookmarked: false,
@@ -65,8 +77,45 @@ export class HomePage implements OnInit {
spaceBetween: 30,
slidesOffsetBefore: 30,
slidesOffsetAfter: 30,
}
};

}

expandArticle(index: number) {
this.selectedArticle = index;

this.slideOpts = {
slidesPerView: 1,
spaceBetween: 0,
slidesOffsetBefore: 0,
slidesOffsetAfter: 0,
};
}

closeArticle() {
this.selectedArticle = null;
this.slideOpts = {
slidesPerView: 1.3,
spaceBetween: 30,
slidesOffsetBefore: 30,
slidesOffsetAfter: 30,
};
}

postComment() {
this.newsData[this.selectedArticle].comments.push({
user: 'Test',
comment: this.myComment,
isLiked: false,
likes: 0,
});

this.myComment = '';
}

scrollToAddComment() {
document.querySelector('#comment-input').scrollIntoView({behavior: "smooth", block: "start"});
}

}

+ 17
- 0
src/global.scss View File

@@ -32,4 +32,21 @@
outline: none;
text-decoration: none;
letter-spacing: 0.5px;
}

.theme-bg-image {
position: fixed;
opacity: 0.1;
width: 100%;
height: 100%;
display: flex;
align-items: flex-start;
justify-content: center;
left: 0;
top: 0;

img {
display: block;
width: 80%;
}
}

Loading…
Cancel
Save