Sfoglia il codice sorgente

Chat UI + softcoding

master
kj1352 5 anni fa
parent
commit
86c9b550ba
11 ha cambiato i file con 451 aggiunte e 16 eliminazioni
  1. +5
    -0
      package-lock.json
  2. +1
    -0
      package.json
  3. +8
    -4
      src/app/app.module.ts
  4. +34
    -1
      src/app/chat-page/chat-page.component.html
  5. +113
    -2
      src/app/chat-page/chat-page.component.scss
  6. +99
    -0
      src/app/chat-page/chat-page.component.ts
  7. +21
    -1
      src/app/chat-page/chat-window/chat-window.component.html
  8. +125
    -0
      src/app/chat-page/chat-window/chat-window.component.scss
  9. +43
    -7
      src/app/chat-page/chat-window/chat-window.component.ts
  10. +1
    -1
      src/app/settings/settings.component.scss
  11. +1
    -0
      src/assets/custom-icons/send.svg

+ 5
- 0
package-lock.json Vedi File

@@ -5410,6 +5410,11 @@
"integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
"dev": true
},
"hammerjs": {
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz",
"integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE="
},
"handle-thing": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",


+ 1
- 0
package.json Vedi File

@@ -21,6 +21,7 @@
"@angular/router": "~9.1.1",
"@angular/service-worker": "~9.1.1",
"angular-svg-icon": "^9.2.0",
"hammerjs": "^2.0.8",
"moment": "^2.27.0",
"ngx-scroll-event": "^1.0.8",
"ngx-siema": "^2.0.1",


+ 8
- 4
src/app/app.module.ts Vedi File

@@ -1,11 +1,14 @@
// Module imports
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AngularSvgIconModule } from 'angular-svg-icon';
import { HttpClientModule } from '@angular/common/http';
import { ScrollEventModule } from 'ngx-scroll-event';
import { NgxSiemaModule } from 'ngx-siema';

import { AppRoutingModule } from './app-routing.module';
import { FormsModule } from '@angular/forms';

// Component imports
import { AppComponent } from './app.component';
import { WelcomeComponent } from './welcome/welcome.component';
import { TabsComponent } from './tabs/tabs.component';
@@ -57,9 +60,10 @@ import { SettingsComponent } from './settings/settings.component';
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule,
ScrollEventModule,
NgxSiemaModule.forRoot(),
HttpClientModule,
ScrollEventModule,
FormsModule,
NgxSiemaModule.forRoot(),
AngularSvgIconModule.forRoot(),
ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production })
],


+ 34
- 1
src/app/chat-page/chat-page.component.html Vedi File

@@ -9,5 +9,38 @@
</h5>
</header>

<section class="upfold"></section>
<section class="segment-buttons">
<button [ngClass]="{'active' : selectedSegment === 'messages'}"
(click)="selectedSegment = 'messages'"> Messages </button>
<button [ngClass]="{'active' : selectedSegment === 'broadcasts'}"
(click)="selectedSegment = 'broadcasts'"> Broadcasts </button>
</section>

<section class="segment-details">

<div *ngIf="selectedSegment === 'messages'">
<ul class="chat-list">
<li *ngFor="let chat of chatList; let i = index" (click)="openChat(i)">
<img src="{{ chat.user.imgUrl }}">
<div class="content">
<label> {{ chat.user.name }} </label>
<p>
{{ chat.conversation[chat.conversation.length - 1].message }}
</p>
</div>
<div class="time-stamp">
{{ getFormattedDate() }}
</div>
</li>
</ul>
</div>

</section>


<section class="chat-window-slideup" [ngClass]="{'active' : selectedChat}">
<app-chat-window [conversation]="selectedChat" *ngIf="selectedChat"
(hideChat)="getChatEvent($event)"></app-chat-window>
</section>

</div>

+ 113
- 2
src/app/chat-page/chat-page.component.scss Vedi File

@@ -45,6 +45,117 @@
}
}

.upfold {
height: 30vh;
.segment-buttons {
display: flex;
align-items: stretch;
height: 40px;
border-radius: 7px;
overflow: hidden;
width: 90%;
margin: 20px auto;
background-color: var(--dark-grey);
padding: 1px;

button {
flex-grow: 1;
border-radius: 7px;
background-color: transparent;
color: white;
font-size: 13px;
border: 0px;

&.active {
background-color: var(--teal-green);
color: white;
font-weight: 500;
}
}
}

.segment-details {
background-color: white;
overflow: auto;
height: calc(100vh - 140px);
padding: 20px 5%;
border-top-left-radius: 30px;
border-top-right-radius: 30px;
}

.chat-list {
list-style: none;

li {
display: flex;
width: 100%;
align-items: center;
justify-content: space-between;
padding: 15px 0;
margin: 0px auto;
border-bottom: 1px solid #cecece;

img {
width: 40px;
height: 40px;
border-radius: 50%;
margin-right: 15px;
}

.content {
max-width: calc(100% - 100px);
flex-grow: 1;
}

.time-stamp {
font-size: 10px;
color: var(--light-grey);
margin-left: 15px;
}

label {
display: block;
font-size: 15px;
font-weight: 500;
color: var(--dark-grey);
}

p {
font-size: 13px;
color: var(--light-grey);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
}

.chat-window-slideup {
position: fixed;
width: 100%;
bottom: 0px;
left: 0px;
height: calc(100vh - 70px);
background-color: white;
z-index: 1;
border-top-left-radius: 30px;
border-top-right-radius: 30px;
transform: translateY(100vh);
opacity: 0;
transition: opacity 0.3s, transform 0.3s;
padding: 40px 0 20px;

&::before {
content: '';
position: absolute;
width: 60px;
height: 4px;
border-radius: 30px;
background-color: var(--light-grey);
left: calc(50% - 30px);
top: 20px;
}

&.active {
opacity: 1;
transform: translateY(0);
}
}

+ 99
- 0
src/app/chat-page/chat-page.component.ts Vedi File

@@ -1,5 +1,6 @@
import { Component, OnInit } from '@angular/core';
import { Location } from '@angular/common';
import * as moment from 'moment';

@Component({
selector: 'app-chat-page',
@@ -7,6 +8,90 @@ import { Location } from '@angular/common';
styleUrls: ['./chat-page.component.scss']
})
export class ChatPageComponent implements OnInit {
selectedSegment: string = 'messages';
selectedChat: any = null;

chatList = [{
user: {
id: 1,
name: 'Jordan Janardhan',
imgUrl: 'https://c-sf.smule.com/rs-s79/arr/c1/0b/83a9328a-1469-4bfd-9e94-622f7ca7b1b5.jpg'
},
conversation: [{
message: 'Hi, What\'s up!?',
user: 1
}, {
message: 'Nothing, Was checking upon you!',
user: 0
}, {
message: 'How you?',
user: 1
}, {
message: 'All Good! you?',
user: 0
}, {
message: 'Dont you feel sad?',
user: 1
}, {
message: 'Why?',
user: 0
}, {
message: 'Cause you flunked the quiz and probably will end up writing a lot of assignments',
user: 1
}, {
message: 'Meh, I will game!',
user: 0
}, {
message: 'Nice! Which game?',
user: 1
}, {
message: 'WOW',
user: 0
}, {
message: 'WOW?',
user: 1
}, {
message: 'World of warcraft you newb!',
user: 0
}]
}, {
user: {
id: 2,
name: 'Sannidhi Mahajan',
imgUrl: 'https://pbs.twimg.com/profile_images/416884752377843712/MW2qg7-f.jpeg'
},
conversation: [{
message: 'Did you get to answer Today\'s Quiz?',
user: 2
}, {
message: 'Yes!, wbu?',
user: 0
}, {
message: 'I Flunked as usual',
user: 0
}, {
message: 'Oh, tats sad! Learn to study daa',
user: 2
}, {
message: 'I topped the class, hehe',
user: 2
}, {
message: 'Did you get to answer Today\'s Quiz?',
user: 2
}, {
message: 'Yes!, wbu?',
user: 0
}, {
message: 'I Flunked as usual',
user: 0
}, {
message: 'Oh, tats sad! Learn to study daa',
user: 2
}, {
message: 'I topped the class, hehe',
user: 2
}]
}];

constructor(
private location: Location
@@ -19,4 +104,18 @@ export class ChatPageComponent implements OnInit {
this.location.back();
}

openChat(index: number) {
this.selectedChat = this.chatList[index];
}

getChatEvent(e: boolean) {
if (e) {
this.selectedChat = null;
}
}

getFormattedDate() {
return moment().format('ddd, hh:MM a')
}

}

+ 21
- 1
src/app/chat-page/chat-window/chat-window.component.html Vedi File

@@ -1 +1,21 @@
<p>chat-window works!</p>
<header>
<h5>
{{ conversation.user.name }}
</h5>

<button (click)="closeChat()"> <svg-icon [applyClass]="true" class="icon" src="assets/custom-icons/close.svg"></svg-icon> </button>
</header>
<ul>
<li *ngFor="let message of conversation.conversation;let i = index"
[ngClass]="{'sent' : message.user === 0, 'received' : message.user !== 0 }"
class="message-{{ i }}">
<div class="message">
{{ message.message }}
</div>
<div class="time-stamp"> {{ getFormattedTime() }} </div>
</li>
</ul>
<div class="input-holder">
<input type="text" placeholder="Type your message" [(ngModel)]="messageText">
<button (click)="sendMessage()"> <svg-icon [applyClass]="true" class="icon" src="assets/custom-icons/send.svg"></svg-icon> </button>
</div>

+ 125
- 0
src/app/chat-page/chat-window/chat-window.component.scss Vedi File

@@ -0,0 +1,125 @@
header {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
padding: 0 5%;
margin: 0 auto 20px;
background-color: white;

h5 {
font-weight: 500;
letter-spacing: 1px;
font-size: 18px;
color: var(--ash-black);
max-width: 50%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

button {
width: 30px;
height: 30px;
border-radius: 50%;
background-color: var(--light-grey);
border: 0px;

.icon {
width: 12px;
height: 12px;
fill: white;
}
}
}

ul {
width: 100%;
margin: 0 auto;
list-style: none;
max-height: calc(100% - 175px);
overflow: auto;
position: absolute;
left: 0px;
bottom: 95px;
padding: 0 5%;

li {
width: 45%;
}

.message {
border-radius: 10px;
padding: 10px;
font-size: 14px;
}

.sent {
margin-left: auto;

.time-stamp {
text-align: right;
}

.message {
color: white;
background-color: var(--teal);
border-bottom-right-radius: 0px;
}
}

.received {
margin-right: auto;

.message {
color: var(--dark-grey);
background-color: rgba(#cecece, 0.4);
border-bottom-left-radius: 0px;
}
}

.time-stamp {
font-size: 12px;
color: var(--dark-grey);
margin: 5px;
}
}

.input-holder {
display: flex;
align-items: stretch;
width: 90%;
margin: 0 auto;
position: absolute;
bottom: 20px;
left: 5%;
border-radius: 30px;
background-color: rgba(#cecece, 0.4);
overflow: hidden;
padding: 5px;

.icon {
fill: white;
width: 15px;
height: 15px;
}

input {
border: 0px;
background-color: transparent;
flex-grow: 1;
padding-left: 10px;
}

button {
width: 40px;
border-radius: 50%;
border: 0px;
height: 40px;
background-color: var(--teal-green);
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0px 0px 5px var(--light-grey);
}
}

+ 43
- 7
src/app/chat-page/chat-window/chat-window.component.ts Vedi File

@@ -1,15 +1,51 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, Input, EventEmitter, Output } from '@angular/core';
import * as moment from 'moment';

@Component({
selector: 'app-chat-window',
templateUrl: './chat-window.component.html',
styleUrls: ['./chat-window.component.scss']
selector: 'app-chat-window',
templateUrl: './chat-window.component.html',
styleUrls: ['./chat-window.component.scss']
})
export class ChatWindowComponent implements OnInit {
@Input() conversation: any;
messageText: string = '';
@Output() hideChat = new EventEmitter();

constructor() { }
constructor() { }

ngOnInit(): void {
}
ngOnInit(): void {
setTimeout(() => {
this.scrollToBottom();
}, 500);
}

getFormattedTime() {
return moment().format('ddd, hh:MM a');
}

sendMessage() {
if (this.messageText.trim()) {
this.conversation.conversation.push({
message: this.messageText,
user: 0,
});

setTimeout(() => {
this.scrollToBottom();
}, 200);

this.messageText = '';
}
}

scrollToBottom() {
document.querySelector('.message-' + (this.conversation.conversation.length - 1)).scrollIntoView({
behavior: 'smooth',
block: 'end'
});
}

closeChat() {
this.hideChat.emit(true);
}
}

+ 1
- 1
src/app/settings/settings.component.scss Vedi File

@@ -56,7 +56,7 @@ li {
border-bottom: 1px solid var(--dark-grey);
height: 70px;
padding: 0 15px;
color: var(--light-grey);
color: rgba(white, 0.7);
font-size: 14px;
letter-spacing: 1px;



+ 1
- 0
src/assets/custom-icons/send.svg Vedi File

@@ -0,0 +1 @@
<svg enable-background="new 0 0 24 24" height="512" viewBox="0 0 24 24" width="512" xmlns="http://www.w3.org/2000/svg"><path d="m8.75 17.612v4.638c0 .324.208.611.516.713.077.025.156.037.234.037.234 0 .46-.11.604-.306l2.713-3.692z"/><path d="m23.685.139c-.23-.163-.532-.185-.782-.054l-22.5 11.75c-.266.139-.423.423-.401.722.023.3.222.556.505.653l6.255 2.138 13.321-11.39-10.308 12.419 10.483 3.583c.078.026.16.04.242.04.136 0 .271-.037.39-.109.19-.116.319-.311.352-.53l2.75-18.5c.041-.28-.077-.558-.307-.722z"/></svg>