Преглед изворни кода

Article Details page transition and UI

master
kj1352 пре 4 година
родитељ
комит
b68f64bcf1
4 измењених фајлова са 462 додато и 40 уклоњено
  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 Прегледај датотеку

@@ -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 Прегледај датотеку

@@ -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 Прегледај датотеку

@@ -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 Прегледај датотеку

@@ -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…
Откажи
Сачувај