mirror of
https://github.com/richard-loafle/fuse-angular.git
synced 2025-01-10 04:25:08 +00:00
Filter pipe added,
spacing class helpers added(margin, padding), Normalize css added, Icon size class helpers added, slideInLeft, slideInRight animation added, Chat app almost completed.
This commit is contained in:
parent
b9569a5ba8
commit
56e6b854c2
|
@ -20,6 +20,7 @@ import { PerfectScrollbarConfigInterface, PerfectScrollbarModule } from 'ngx-per
|
||||||
import { HttpModule } from '@angular/http';
|
import { HttpModule } from '@angular/http';
|
||||||
import { InMemoryWebApiModule } from 'angular-in-memory-web-api';
|
import { InMemoryWebApiModule } from 'angular-in-memory-web-api';
|
||||||
import { FuseFakeDbService } from './fuse-fake-db/fuse-fake-db.service';
|
import { FuseFakeDbService } from './fuse-fake-db/fuse-fake-db.service';
|
||||||
|
import { INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS } from '@angular/platform-browser-dynamic/src/platform_providers';
|
||||||
|
|
||||||
const PERFECT_SCROLLBAR_CONFIG: PerfectScrollbarConfigInterface = {
|
const PERFECT_SCROLLBAR_CONFIG: PerfectScrollbarConfigInterface = {
|
||||||
suppressScrollX: true
|
suppressScrollX: true
|
||||||
|
@ -30,6 +31,10 @@ const appRoutes: Routes = [
|
||||||
path : 'apps/mail',
|
path : 'apps/mail',
|
||||||
loadChildren: './main/apps/mail/mail.module#MailModule'
|
loadChildren: './main/apps/mail/mail.module#MailModule'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path : 'apps/chat',
|
||||||
|
loadChildren: './main/apps/chat/chat.module#ChatModule'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path : '**',
|
path : '**',
|
||||||
redirectTo: 'apps/dashboards/project'
|
redirectTo: 'apps/dashboards/project'
|
||||||
|
|
|
@ -8,4 +8,16 @@ export class Animations
|
||||||
transition('1 => 0', animate('300ms ease-out')),
|
transition('1 => 0', animate('300ms ease-out')),
|
||||||
transition('0 => 1', animate('300ms ease-in'))
|
transition('0 => 1', animate('300ms ease-in'))
|
||||||
]);
|
]);
|
||||||
|
public static slideInLeft = trigger('slideInLeft', [
|
||||||
|
state('void', style({transform: 'translateX(-100%)', display: 'none'})),
|
||||||
|
state('*', style({transform: 'translateX(0)', display: 'flex'})),
|
||||||
|
transition('void => *', animate('300ms')),
|
||||||
|
transition('* => void', animate('300ms'))
|
||||||
|
]);
|
||||||
|
public static slideInRight = trigger('slideInRight', [
|
||||||
|
state('void', style({transform: 'translateX(100%)', display: 'none'})),
|
||||||
|
state('*', style({transform: 'translateX(0)', display: 'flex'})),
|
||||||
|
transition('void => *', animate('300ms')),
|
||||||
|
transition('* => void', animate('300ms'))
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
|
|
||||||
import { MaterialModule } from './material.module';
|
import { MaterialModule } from './material.module';
|
||||||
|
@ -23,7 +23,8 @@ import { FusePipesModule } from '../pipes/pipes.module';
|
||||||
CommonModule,
|
CommonModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
FusePipesModule,
|
FusePipesModule,
|
||||||
PerfectScrollbarModule
|
PerfectScrollbarModule,
|
||||||
|
ReactiveFormsModule
|
||||||
],
|
],
|
||||||
exports : [
|
exports : [
|
||||||
FlexLayoutModule,
|
FlexLayoutModule,
|
||||||
|
@ -33,7 +34,8 @@ import { FusePipesModule } from '../pipes/pipes.module';
|
||||||
FuseMdSidenavHelperDirective,
|
FuseMdSidenavHelperDirective,
|
||||||
FuseMdSidenavTogglerDirective,
|
FuseMdSidenavTogglerDirective,
|
||||||
FusePipesModule,
|
FusePipesModule,
|
||||||
PerfectScrollbarModule
|
PerfectScrollbarModule,
|
||||||
|
ReactiveFormsModule
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
152
src/app/core/pipes/filter.pipe.ts
Normal file
152
src/app/core/pipes/filter.pipe.ts
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
/**
|
||||||
|
* Created by vadimdez on 28/06/16.
|
||||||
|
*/
|
||||||
|
import { Pipe, Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
@Pipe({
|
||||||
|
name: 'filterBy',
|
||||||
|
pure: false
|
||||||
|
})
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class FilterPipe {
|
||||||
|
|
||||||
|
private filterByString(filter) {
|
||||||
|
if (filter) {
|
||||||
|
filter = filter.toLowerCase();
|
||||||
|
}
|
||||||
|
return value => {
|
||||||
|
return !filter || (value ? ('' + value).toLowerCase().indexOf(filter) !== -1 : false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private filterByBoolean(filter) {
|
||||||
|
return value => {
|
||||||
|
return Boolean(value) === filter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private filterByObject(filter) {
|
||||||
|
return value => {
|
||||||
|
for (let key in filter) {
|
||||||
|
|
||||||
|
if (key === '$or') {
|
||||||
|
if (!this.filterByOr(filter.$or)(this.getValue(value))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!value.hasOwnProperty(key) && !Object.getOwnPropertyDescriptor(Object.getPrototypeOf(value), key)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let val = this.getValue(value[key]);
|
||||||
|
const filterType = typeof filter[key];
|
||||||
|
let isMatching;
|
||||||
|
|
||||||
|
if (filterType === 'boolean') {
|
||||||
|
isMatching = this.filterByBoolean(filter[key])(val);
|
||||||
|
} else if (filterType === 'string') {
|
||||||
|
isMatching = this.filterByString(filter[key])(val);
|
||||||
|
} else if (filterType === 'object') {
|
||||||
|
isMatching = this.filterByObject(filter[key])(val);
|
||||||
|
} else {
|
||||||
|
isMatching = this.filterDefault(filter[key])(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isMatching) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter value by $or
|
||||||
|
*
|
||||||
|
* @param filter
|
||||||
|
* @returns {(value:any)=>boolean}
|
||||||
|
*/
|
||||||
|
private filterByOr(filter: any[]) {
|
||||||
|
return (value: any) => {
|
||||||
|
let hasMatch = false;
|
||||||
|
const length = filter.length;
|
||||||
|
const isArray = value instanceof Array;
|
||||||
|
|
||||||
|
const arrayComparison = (i) => {
|
||||||
|
return value.indexOf(filter[i]) !== -1;
|
||||||
|
};
|
||||||
|
const otherComparison = (i) => {
|
||||||
|
return value === filter[i];
|
||||||
|
};
|
||||||
|
const comparison = isArray ? arrayComparison : otherComparison;
|
||||||
|
|
||||||
|
for (let i = 0; i < length; i++) {
|
||||||
|
if (comparison(i)) {
|
||||||
|
hasMatch = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasMatch;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks function's value if type is function otherwise same value
|
||||||
|
* @param value
|
||||||
|
* @returns {any}
|
||||||
|
*/
|
||||||
|
private getValue(value: any) {
|
||||||
|
return typeof value === 'function' ? value() : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defatul filterDefault function
|
||||||
|
*
|
||||||
|
* @param filter
|
||||||
|
* @returns {(value:any)=>boolean}
|
||||||
|
*/
|
||||||
|
private filterDefault(filter) {
|
||||||
|
return value => {
|
||||||
|
return filter === undefined || filter == value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private isNumber(value) {
|
||||||
|
return !isNaN(parseInt(value, 10)) && isFinite(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
transform(array: any[], filter: any): any {
|
||||||
|
const type = typeof filter;
|
||||||
|
|
||||||
|
if (!array) {
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'boolean') {
|
||||||
|
return array.filter(this.filterByBoolean(filter));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'string') {
|
||||||
|
if (this.isNumber(filter)) {
|
||||||
|
return array.filter(this.filterDefault(filter));
|
||||||
|
}
|
||||||
|
|
||||||
|
return array.filter(this.filterByString(filter));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'object') {
|
||||||
|
return array.filter(this.filterByObject(filter));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'function') {
|
||||||
|
return array.filter(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
return array.filter(this.filterDefault(filter));
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,20 +4,24 @@ import { KeysPipe } from './keys.pipe';
|
||||||
import { GetByIdPipe } from './getById.pipe';
|
import { GetByIdPipe } from './getById.pipe';
|
||||||
import { HtmlToPlaintextPipe } from './htmlToPlaintext.pipe';
|
import { HtmlToPlaintextPipe } from './htmlToPlaintext.pipe';
|
||||||
import { SearchPipe } from './search.pipe';
|
import { SearchPipe } from './search.pipe';
|
||||||
|
import { FilterPipe } from './filter.pipe';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
KeysPipe,
|
KeysPipe,
|
||||||
GetByIdPipe,
|
GetByIdPipe,
|
||||||
HtmlToPlaintextPipe,
|
HtmlToPlaintextPipe,
|
||||||
SearchPipe
|
SearchPipe,
|
||||||
|
FilterPipe
|
||||||
|
|
||||||
],
|
],
|
||||||
imports : [],
|
imports : [],
|
||||||
exports : [
|
exports : [
|
||||||
KeysPipe,
|
KeysPipe,
|
||||||
GetByIdPipe,
|
GetByIdPipe,
|
||||||
HtmlToPlaintextPipe,
|
HtmlToPlaintextPipe,
|
||||||
SearchPipe
|
SearchPipe,
|
||||||
|
FilterPipe
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -20,12 +20,16 @@
|
||||||
@include angular-material-typography($custom-typography);
|
@include angular-material-typography($custom-typography);
|
||||||
|
|
||||||
// Partials
|
// Partials
|
||||||
|
@import "partials/normalize";
|
||||||
|
@import "partials/spacing";
|
||||||
@import "partials/global";
|
@import "partials/global";
|
||||||
@import "partials/_material";
|
@import "partials/icons";
|
||||||
|
@import "partials/material";
|
||||||
@import "partials/angular-material-fix";
|
@import "partials/angular-material-fix";
|
||||||
@import "partials/typography";
|
@import "partials/typography";
|
||||||
@import "partials/page-layouts";
|
@import "partials/page-layouts";
|
||||||
@import "partials/navigation";
|
@import "partials/navigation";
|
||||||
|
@import "partials/forms";
|
||||||
|
|
||||||
// Plugins
|
// Plugins
|
||||||
@import "partials/plugins/plugins";
|
@import "partials/plugins/plugins";
|
||||||
|
|
15
src/app/core/scss/partials/_forms.scss
Normal file
15
src/app/core/scss/partials/_forms.scss
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
button,
|
||||||
|
input[type=email],
|
||||||
|
input[type=tel],
|
||||||
|
input[type=text],
|
||||||
|
input[type=password],
|
||||||
|
input[type=image],
|
||||||
|
input[type=submit],
|
||||||
|
input[type=button],
|
||||||
|
input[type=search],
|
||||||
|
textarea {
|
||||||
|
appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
outline: none;
|
||||||
|
}
|
|
@ -2,6 +2,10 @@
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
html, body {
|
html, body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
22
src/app/core/scss/partials/_icons.scss
Normal file
22
src/app/core/scss/partials/_icons.scss
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
i,
|
||||||
|
md-icon {
|
||||||
|
color: rgba(0, 0, 0, 0.54);
|
||||||
|
font-size: 24px;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
min-width: 24px;
|
||||||
|
min-height: 24px;
|
||||||
|
line-height: 24px;
|
||||||
|
|
||||||
|
@for $size from 2 through 128 {
|
||||||
|
|
||||||
|
&.s-#{$size * 2} {
|
||||||
|
font-size: #{($size * 2) + 'px'} !important;
|
||||||
|
width: #{($size * 2) + 'px'} !important;
|
||||||
|
height: #{($size * 2) + 'px'} !important;
|
||||||
|
min-width: #{($size * 2) + 'px'} !important;
|
||||||
|
min-height: #{($size * 2) + 'px'} !important;
|
||||||
|
line-height: #{($size * 2) + 'px'} !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -39,6 +39,54 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.avatar-wrapper {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
md-icon.status {
|
||||||
|
position: absolute;
|
||||||
|
top: 28px;
|
||||||
|
left: 28px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
md-icon.status {
|
||||||
|
border-radius: 50%;
|
||||||
|
|
||||||
|
&.online {
|
||||||
|
color: #4CAF50;
|
||||||
|
&:before {
|
||||||
|
content: "check_circle";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.do-not-disturb {
|
||||||
|
color: #F44336;
|
||||||
|
&:before {
|
||||||
|
content: "do_not_disturb_on";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.away {
|
||||||
|
background-color: #FFC107;
|
||||||
|
color: #FFFFFF;
|
||||||
|
&:before {
|
||||||
|
content: "access_time";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.offline {
|
||||||
|
color: #646464;
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
&:before {
|
||||||
|
content: "not_interested";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*----------------------------------------------------------------*/
|
/*----------------------------------------------------------------*/
|
||||||
/* Forms
|
/* Forms
|
||||||
/*----------------------------------------------------------------*/
|
/*----------------------------------------------------------------*/
|
||||||
|
|
447
src/app/core/scss/partials/_normalize.scss
Normal file
447
src/app/core/scss/partials/_normalize.scss
Normal file
|
@ -0,0 +1,447 @@
|
||||||
|
/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */
|
||||||
|
|
||||||
|
/* Document
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the line height in all browsers.
|
||||||
|
* 2. Prevent adjustments of font size after orientation changes in
|
||||||
|
* IE on Windows Phone and in iOS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
html {
|
||||||
|
line-height: 1.15; /* 1 */
|
||||||
|
-ms-text-size-adjust: 100%; /* 2 */
|
||||||
|
-webkit-text-size-adjust: 100%; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sections
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the margin in all browsers (opinionated).
|
||||||
|
*/
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in IE 9-.
|
||||||
|
*/
|
||||||
|
|
||||||
|
article,
|
||||||
|
aside,
|
||||||
|
footer,
|
||||||
|
header,
|
||||||
|
nav,
|
||||||
|
section {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the font size and margin on `h1` elements within `section` and
|
||||||
|
* `article` contexts in Chrome, Firefox, and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 2em;
|
||||||
|
margin: 0.67em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Grouping content
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in IE 9-.
|
||||||
|
* 1. Add the correct display in IE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
figcaption,
|
||||||
|
figure,
|
||||||
|
main { /* 1 */
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct margin in IE 8.
|
||||||
|
*/
|
||||||
|
|
||||||
|
figure {
|
||||||
|
margin: 1em 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Add the correct box sizing in Firefox.
|
||||||
|
* 2. Show the overflow in Edge and IE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
hr {
|
||||||
|
box-sizing: content-box; /* 1 */
|
||||||
|
height: 0; /* 1 */
|
||||||
|
overflow: visible; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||||
|
* 2. Correct the odd `em` font sizing in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pre {
|
||||||
|
font-family: monospace, monospace; /* 1 */
|
||||||
|
font-size: 1em; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Text-level semantics
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Remove the gray background on active links in IE 10.
|
||||||
|
* 2. Remove gaps in links underline in iOS 8+ and Safari 8+.
|
||||||
|
*/
|
||||||
|
|
||||||
|
a {
|
||||||
|
background-color: transparent; /* 1 */
|
||||||
|
-webkit-text-decoration-skip: objects; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Remove the bottom border in Chrome 57- and Firefox 39-.
|
||||||
|
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
abbr[title] {
|
||||||
|
border-bottom: none; /* 1 */
|
||||||
|
text-decoration: underline; /* 2 */
|
||||||
|
text-decoration: underline dotted; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent the duplicate application of `bolder` by the next rule in Safari 6.
|
||||||
|
*/
|
||||||
|
|
||||||
|
b,
|
||||||
|
strong {
|
||||||
|
font-weight: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct font weight in Chrome, Edge, and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
b,
|
||||||
|
strong {
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||||
|
* 2. Correct the odd `em` font sizing in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
code,
|
||||||
|
kbd,
|
||||||
|
samp {
|
||||||
|
font-family: monospace, monospace; /* 1 */
|
||||||
|
font-size: 1em; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct font style in Android 4.3-.
|
||||||
|
*/
|
||||||
|
|
||||||
|
dfn {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct background and color in IE 9-.
|
||||||
|
*/
|
||||||
|
|
||||||
|
mark {
|
||||||
|
background-color: #ff0;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct font size in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
small {
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent `sub` and `sup` elements from affecting the line height in
|
||||||
|
* all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
sub,
|
||||||
|
sup {
|
||||||
|
font-size: 75%;
|
||||||
|
line-height: 0;
|
||||||
|
position: relative;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub {
|
||||||
|
bottom: -0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
sup {
|
||||||
|
top: -0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Embedded content
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in IE 9-.
|
||||||
|
*/
|
||||||
|
|
||||||
|
audio,
|
||||||
|
video {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in iOS 4-7.
|
||||||
|
*/
|
||||||
|
|
||||||
|
audio:not([controls]) {
|
||||||
|
display: none;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the border on images inside links in IE 10-.
|
||||||
|
*/
|
||||||
|
|
||||||
|
img {
|
||||||
|
border-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide the overflow in IE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
svg:not(:root) {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Forms
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Change the font styles in all browsers (opinionated).
|
||||||
|
* 2. Remove the margin in Firefox and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
input,
|
||||||
|
optgroup,
|
||||||
|
select,
|
||||||
|
textarea {
|
||||||
|
font-family: sans-serif; /* 1 */
|
||||||
|
font-size: 100%; /* 1 */
|
||||||
|
line-height: 1.15; /* 1 */
|
||||||
|
margin: 0; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the overflow in IE.
|
||||||
|
* 1. Show the overflow in Edge.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
input { /* 1 */
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the inheritance of text transform in Edge, Firefox, and IE.
|
||||||
|
* 1. Remove the inheritance of text transform in Firefox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
select { /* 1 */
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`
|
||||||
|
* controls in Android 4.
|
||||||
|
* 2. Correct the inability to style clickable types in iOS and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
html [type="button"], /* 1 */
|
||||||
|
[type="reset"],
|
||||||
|
[type="submit"] {
|
||||||
|
-webkit-appearance: button; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the inner border and padding in Firefox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button::-moz-focus-inner,
|
||||||
|
[type="button"]::-moz-focus-inner,
|
||||||
|
[type="reset"]::-moz-focus-inner,
|
||||||
|
[type="submit"]::-moz-focus-inner {
|
||||||
|
border-style: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restore the focus styles unset by the previous rule.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button:-moz-focusring,
|
||||||
|
[type="button"]:-moz-focusring,
|
||||||
|
[type="reset"]:-moz-focusring,
|
||||||
|
[type="submit"]:-moz-focusring {
|
||||||
|
outline: 1px dotted ButtonText;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the padding in Firefox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
padding: 0.35em 0.75em 0.625em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the text wrapping in Edge and IE.
|
||||||
|
* 2. Correct the color inheritance from `fieldset` elements in IE.
|
||||||
|
* 3. Remove the padding so developers are not caught out when they zero out
|
||||||
|
* `fieldset` elements in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
legend {
|
||||||
|
box-sizing: border-box; /* 1 */
|
||||||
|
color: inherit; /* 2 */
|
||||||
|
display: table; /* 1 */
|
||||||
|
max-width: 100%; /* 1 */
|
||||||
|
padding: 0; /* 3 */
|
||||||
|
white-space: normal; /* 1 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Add the correct display in IE 9-.
|
||||||
|
* 2. Add the correct vertical alignment in Chrome, Firefox, and Opera.
|
||||||
|
*/
|
||||||
|
|
||||||
|
progress {
|
||||||
|
display: inline-block; /* 1 */
|
||||||
|
vertical-align: baseline; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the default vertical scrollbar in IE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Add the correct box sizing in IE 10-.
|
||||||
|
* 2. Remove the padding in IE 10-.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[type="checkbox"],
|
||||||
|
[type="radio"] {
|
||||||
|
box-sizing: border-box; /* 1 */
|
||||||
|
padding: 0; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the cursor style of increment and decrement buttons in Chrome.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[type="number"]::-webkit-inner-spin-button,
|
||||||
|
[type="number"]::-webkit-outer-spin-button {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the odd appearance in Chrome and Safari.
|
||||||
|
* 2. Correct the outline style in Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[type="search"] {
|
||||||
|
-webkit-appearance: textfield; /* 1 */
|
||||||
|
outline-offset: -2px; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the inner padding and cancel buttons in Chrome and Safari on macOS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[type="search"]::-webkit-search-cancel-button,
|
||||||
|
[type="search"]::-webkit-search-decoration {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the inability to style clickable types in iOS and Safari.
|
||||||
|
* 2. Change font properties to `inherit` in Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
::-webkit-file-upload-button {
|
||||||
|
-webkit-appearance: button; /* 1 */
|
||||||
|
font: inherit; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Interactive
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the correct display in IE 9-.
|
||||||
|
* 1. Add the correct display in Edge, IE, and Firefox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
details, /* 1 */
|
||||||
|
menu {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the correct display in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
summary {
|
||||||
|
display: list-item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scripting
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in IE 9-.
|
||||||
|
*/
|
||||||
|
|
||||||
|
canvas {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in IE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hidden
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in IE 10-.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[hidden] {
|
||||||
|
display: none;
|
||||||
|
}
|
62
src/app/core/scss/partials/_spacing.scss
Normal file
62
src/app/core/scss/partials/_spacing.scss
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
// Margin and Padding
|
||||||
|
@each $prop, $abbrev in (margin: m, padding: p) {
|
||||||
|
|
||||||
|
@for $index from 0 through 64 {
|
||||||
|
$size: $index *4;
|
||||||
|
$length: #{$size}px;
|
||||||
|
.#{$abbrev}-#{$size} {
|
||||||
|
#{$prop}: $length !important;
|
||||||
|
}
|
||||||
|
.#{$abbrev}t-#{$size} {
|
||||||
|
#{$prop}-top: $length !important;
|
||||||
|
}
|
||||||
|
.#{$abbrev}r-#{$size} {
|
||||||
|
#{$prop}-right: $length !important;
|
||||||
|
}
|
||||||
|
.#{$abbrev}b-#{$size} {
|
||||||
|
#{$prop}-bottom: $length !important;
|
||||||
|
}
|
||||||
|
.#{$abbrev}l-#{$size} {
|
||||||
|
#{$prop}-left: $length !important;
|
||||||
|
}
|
||||||
|
.#{$abbrev}x-#{$size} {
|
||||||
|
#{$prop}-right: $length !important;
|
||||||
|
#{$prop}-left: $length !important;
|
||||||
|
}
|
||||||
|
.#{$abbrev}y-#{$size} {
|
||||||
|
#{$prop}-top: $length !important;
|
||||||
|
#{$prop}-bottom: $length !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some special margin utils
|
||||||
|
.m-auto {
|
||||||
|
margin: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt-auto {
|
||||||
|
margin-top: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mr-auto {
|
||||||
|
margin-right: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-auto {
|
||||||
|
margin-bottom: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ml-auto {
|
||||||
|
margin-left: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx-auto {
|
||||||
|
margin-right: auto !important;
|
||||||
|
margin-left: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.my-auto {
|
||||||
|
margin-top: auto !important;
|
||||||
|
margin-bottom: auto !important;
|
||||||
|
}
|
325
src/app/fuse-fake-db/chat.ts
Normal file
325
src/app/fuse-fake-db/chat.ts
Normal file
|
@ -0,0 +1,325 @@
|
||||||
|
export class ChatFakeDb
|
||||||
|
{
|
||||||
|
public static contacts = [
|
||||||
|
{
|
||||||
|
'id' : '5725a680b3249760ea21de52',
|
||||||
|
'name' : 'Alice Freeman',
|
||||||
|
'avatar': 'assets/images/avatars/alice.jpg',
|
||||||
|
'status': 'online',
|
||||||
|
'mood' : 'I never sign anything until I pretend to read it first..'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : '5725a680606588342058356d',
|
||||||
|
'name' : 'Arnold',
|
||||||
|
'avatar': 'assets/images/avatars/Arnold.jpg',
|
||||||
|
'status': 'do-not-disturb',
|
||||||
|
'mood' : 'Looks like Andrew Jackson\'s been tossed to the back of the bus.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : '5725a68009e20d0a9e9acf2a',
|
||||||
|
'name' : 'Barrera',
|
||||||
|
'avatar': 'assets/images/avatars/Barrera.jpg',
|
||||||
|
'status': 'do-not-disturb',
|
||||||
|
'mood' : 'Love is going to bed early.Marriage is going to sleep early.',
|
||||||
|
'unread': null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : '5725a6809fdd915739187ed5',
|
||||||
|
'name' : 'Blair',
|
||||||
|
'avatar': 'assets/images/avatars/Blair.jpg',
|
||||||
|
'status': 'offline',
|
||||||
|
'mood' : 'I would be unstoppable. If i could just get started.',
|
||||||
|
'unread': 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : '5725a68007920cf75051da64',
|
||||||
|
'name' : 'Boyle',
|
||||||
|
'avatar': 'assets/images/avatars/Boyle.jpg',
|
||||||
|
'status': 'offline',
|
||||||
|
'mood' : '\'GOOD MORNING COFFEE\'....Meet your maker!!!!'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : '5725a68031fdbb1db2c1af47',
|
||||||
|
'name' : 'Christy',
|
||||||
|
'avatar': 'assets/images/avatars/Christy.jpg',
|
||||||
|
'status': 'offline',
|
||||||
|
'mood' : 'We always hold hands. If I let go, she shops.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : '5725a680bc670af746c435e2',
|
||||||
|
'name' : 'Copeland',
|
||||||
|
'avatar': 'assets/images/avatars/Copeland.jpg',
|
||||||
|
'status': 'online',
|
||||||
|
'mood' : 'I get enough exercise just pushing my luck.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : '5725a680e7eb988a58ddf303',
|
||||||
|
'name' : 'Estes',
|
||||||
|
'avatar': 'assets/images/avatars/Estes.jpg',
|
||||||
|
'status': 'away',
|
||||||
|
'mood' : 'What comes after the man bun hairstyle? The he-hive!',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : '5725a680dcb077889f758961',
|
||||||
|
'name' : 'Harper',
|
||||||
|
'avatar': 'assets/images/avatars/Harper.jpg',
|
||||||
|
'status': 'offline',
|
||||||
|
'mood' : 'Always try to be modest and be proud of it!',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : '5725a6806acf030f9341e925',
|
||||||
|
'name' : 'Helen',
|
||||||
|
'avatar': 'assets/images/avatars/Helen.jpg',
|
||||||
|
'status': 'away',
|
||||||
|
'mood' : 'Why are there stitch marks on zombies? Who\'s giving them medical attention?',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : '5725a680ae1ae9a3c960d487',
|
||||||
|
'name' : 'Henderson',
|
||||||
|
'avatar': 'assets/images/avatars/Henderson.jpg',
|
||||||
|
'status': 'offline',
|
||||||
|
'mood' : 'I can\'t decide if people who wear pajamas in public have given up on life or are living it to the fullest.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : '5725a680b8d240c011dd224b',
|
||||||
|
'name' : 'Josefina',
|
||||||
|
'avatar': 'assets/images/avatars/Josefina.jpg',
|
||||||
|
'status': 'online',
|
||||||
|
'mood' : 'The fastest way to being happy is to make other people happy. You go first',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : '5725a68034cb3968e1f79eac',
|
||||||
|
'name' : 'Katina',
|
||||||
|
'avatar': 'assets/images/avatars/Katina.jpg',
|
||||||
|
'status': 'away',
|
||||||
|
'mood' : 'If I was a rat,,, I wouldn\'t give anyone my ass.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : '5725a6801146cce777df2a08',
|
||||||
|
'name' : 'Lily',
|
||||||
|
'avatar': 'assets/images/avatars/Lily.jpg',
|
||||||
|
'status': 'do-not-disturb',
|
||||||
|
'mood' : 'A zip line but from the sofa to the fridge',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : '5725a6808a178bfd034d6ecf',
|
||||||
|
'name' : 'Mai',
|
||||||
|
'avatar': 'assets/images/avatars/Mai.jpg',
|
||||||
|
'status': 'away',
|
||||||
|
'mood' : 'If a girl tells you she has a nipple ring, the only correct response is \'I don\'t believe you.\'',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : '5725a680653c265f5c79b5a9',
|
||||||
|
'name' : 'Nancy',
|
||||||
|
'avatar': 'assets/images/avatars/Nancy.jpg',
|
||||||
|
'status': 'do-not-disturb',
|
||||||
|
'mood' : 'Prison counts as a gated community, right?',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : '5725a680bbcec3cc32a8488a',
|
||||||
|
'name' : 'Nora',
|
||||||
|
'avatar': 'assets/images/avatars/Nora.jpg',
|
||||||
|
'status': 'do-not-disturb',
|
||||||
|
'mood' : 'I never date left handed women. Righty tighty, lefty loosey.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : '5725a6803d87f1b77e17b62b',
|
||||||
|
'name' : 'Odessa',
|
||||||
|
'avatar': 'assets/images/avatars/Odessa.jpg',
|
||||||
|
'status': 'away',
|
||||||
|
'mood' : 'A day without sunshine is like, night.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : '5725a680e87cb319bd9bd673',
|
||||||
|
'name' : 'Reyna',
|
||||||
|
'avatar': 'assets/images/avatars/Reyna.jpg',
|
||||||
|
'status': 'offline',
|
||||||
|
'mood' : 'I can\'t wait for summer in Canada...',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : '5725a6802d10e277a0f35775',
|
||||||
|
'name' : 'Shauna',
|
||||||
|
'avatar': 'assets/images/avatars/Shauna.jpg',
|
||||||
|
'status': 'online',
|
||||||
|
'mood' : 'My take home pay doesn’t ven take me home.',
|
||||||
|
'unread': null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : '5725a680aef1e5cf26dd3d1f',
|
||||||
|
'name' : 'Shepard',
|
||||||
|
'avatar': 'assets/images/avatars/Shepard.jpg',
|
||||||
|
'status': 'online',
|
||||||
|
'mood' : 'I don\'t speak Spanish, but I\'m pretty sure \'Dora\' means \'annoying\'',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : '5725a680cd7efa56a45aea5d',
|
||||||
|
'name' : 'Tillman',
|
||||||
|
'avatar': 'assets/images/avatars/Tillman.jpg',
|
||||||
|
'status': 'do-not-disturb',
|
||||||
|
'mood' : '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : '5725a680fb65c91a82cb35e2',
|
||||||
|
'name' : 'Trevino',
|
||||||
|
'avatar': 'assets/images/avatars/Trevino.jpg',
|
||||||
|
'status': 'away',
|
||||||
|
'mood' : 'Apparently, a rat and a plastic tube does not count as a DIY abortion kit.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : '5725a68018c663044be49cbf',
|
||||||
|
'name' : 'Tyson',
|
||||||
|
'avatar': 'assets/images/avatars/Tyson.jpg',
|
||||||
|
'status': 'do-not-disturb',
|
||||||
|
'mood' : 'I\'m wondering why life keeps teaching me lessons I have no desire to learn...',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : '5725a6809413bf8a0a5272b1',
|
||||||
|
'name' : 'Velazquez',
|
||||||
|
'avatar': 'assets/images/avatars/Velazquez.jpg',
|
||||||
|
'status': 'online',
|
||||||
|
'mood' : 'Modulation in all things.',
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
public static chats = [
|
||||||
|
{
|
||||||
|
'id' : '1725a680b3249760ea21de52',
|
||||||
|
'dialog': [
|
||||||
|
{
|
||||||
|
'who' : '5725a680b3249760ea21de52',
|
||||||
|
'message': 'Quickly come to the meeting room 1B, we have a big server issue',
|
||||||
|
'time' : '2017-03-22T08:54:28.299Z'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'who' : '5725a6802d10e277a0f35724',
|
||||||
|
'message': 'I’m having breakfast right now, can’t you wait for 10 minutes?',
|
||||||
|
'time' : '2017-03-22T08:55:28.299Z'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'who' : '5725a680b3249760ea21de52',
|
||||||
|
'message': 'We are losing money! Quick!',
|
||||||
|
'time' : '2017-03-22T09:00:28.299Z'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'who' : '5725a6802d10e277a0f35724',
|
||||||
|
'message': 'It’s not my money, you know. I will eat my breakfast and then I will come to the meeting room.',
|
||||||
|
'time' : '2017-03-22T09:02:28.299Z'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'who' : '5725a680b3249760ea21de52',
|
||||||
|
'message': 'You are the worst!',
|
||||||
|
'time' : '2017-03-22T09:05:28.299Z'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'who' : '5725a680b3249760ea21de52',
|
||||||
|
'message': 'We are losing money! Quick!',
|
||||||
|
'time' : '2017-03-22T09:15:28.299Z'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'who' : '5725a6802d10e277a0f35724',
|
||||||
|
'message': 'It’s not my money, you know. I will eat my breakfast and then I will come to the meeting room.',
|
||||||
|
'time' : '2017-03-22T09:20:28.299Z'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'who' : '5725a680b3249760ea21de52',
|
||||||
|
'message': 'You are the worst!',
|
||||||
|
'time' : '2017-03-22T09:22:28.299Z'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'who' : '5725a680b3249760ea21de52',
|
||||||
|
'message': 'We are losing money! Quick!',
|
||||||
|
'time' : '2017-03-22T09:25:28.299Z'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'who' : '5725a6802d10e277a0f35724',
|
||||||
|
'message': 'It’s not my money, you know. I will eat my breakfast and then I will come to the meeting room.',
|
||||||
|
'time' : '2017-03-22T09:27:28.299Z'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'who' : '5725a680b3249760ea21de52',
|
||||||
|
'message': 'You are the worst!',
|
||||||
|
'time' : '2017-03-22T09:33:28.299Z'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'who' : '5725a680b3249760ea21de52',
|
||||||
|
'message': 'We are losing money! Quick!',
|
||||||
|
'time' : '2017-03-22T09:35:28.299Z'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'who' : '5725a6802d10e277a0f35724',
|
||||||
|
'message': 'It’s not my money, you know. I will eat my breakfast and then I will come to the meeting room.',
|
||||||
|
'time' : '2017-03-22T09:45:28.299Z'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'who' : '5725a680b3249760ea21de52',
|
||||||
|
'message': 'You are the worst!',
|
||||||
|
'time' : '2017-03-22T10:00:28.299Z'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : '2725a680b8d240c011dd2243',
|
||||||
|
'dialog': [
|
||||||
|
{
|
||||||
|
'who' : '5725a680b8d240c011dd224b',
|
||||||
|
'message': 'Quickly come to the meeting room 1B, we have a big server issue',
|
||||||
|
'time' : '2017-04-22T01:00:00.299Z'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'who' : '5725a6802d10e277a0f35724',
|
||||||
|
'message': 'I’m having breakfast right now, can’t you wait for 10 minutes?',
|
||||||
|
'time' : '2017-04-22T01:05:00.299Z'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'who' : '5725a680b8d240c011dd224b',
|
||||||
|
'message': 'We are losing money! Quick!',
|
||||||
|
'time' : '2017-04-22T01:10:00.299Z'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : '3725a6809413bf8a0a5272b4',
|
||||||
|
'dialog': [
|
||||||
|
{
|
||||||
|
'who' : '5725a6809413bf8a0a5272b1',
|
||||||
|
'message': 'Quickly come to the meeting room 1B, we have a big server issue',
|
||||||
|
'time' : '2017-04-22T02:10:00.299Z'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
public static user = [
|
||||||
|
{
|
||||||
|
'id' : '5725a6802d10e277a0f35724',
|
||||||
|
'name' : 'John Doe',
|
||||||
|
'avatar' : 'assets/images/avatars/profile.jpg',
|
||||||
|
'status' : 'online',
|
||||||
|
'mood' : 'it\'s a status....not your diary...',
|
||||||
|
'chatList': [
|
||||||
|
{
|
||||||
|
'id' : '1725a680b3249760ea21de52',
|
||||||
|
'contactId' : '5725a680b3249760ea21de52',
|
||||||
|
'name' : 'Alice Freeman',
|
||||||
|
'unread' : 4,
|
||||||
|
'lastMessageTime': '2017-06-12T02:10:18.931Z'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : '2725a680b8d240c011dd2243',
|
||||||
|
'contactId' : '5725a680b8d240c011dd224b',
|
||||||
|
'name' : 'Josefina',
|
||||||
|
'unread' : null,
|
||||||
|
'lastMessageTime': '2017-02-18T10:30:18.931Z'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : '3725a6809413bf8a0a5272b4',
|
||||||
|
'contactId' : '5725a6809413bf8a0a5272b1',
|
||||||
|
'name' : 'Velazquez',
|
||||||
|
'unread' : 2,
|
||||||
|
'lastMessageTime': '2017-03-18T12:30:18.931Z'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
import {InMemoryDbService} from 'angular-in-memory-web-api';
|
import {InMemoryDbService} from 'angular-in-memory-web-api';
|
||||||
import {MailFakeDb} from './mail';
|
import {MailFakeDb} from './mail';
|
||||||
|
import {ChatFakeDb} from './chat';
|
||||||
|
|
||||||
export class FuseFakeDbService implements InMemoryDbService
|
export class FuseFakeDbService implements InMemoryDbService
|
||||||
{
|
{
|
||||||
|
@ -8,7 +9,10 @@ export class FuseFakeDbService implements InMemoryDbService
|
||||||
return {
|
return {
|
||||||
'mail-mails' : MailFakeDb.mails,
|
'mail-mails' : MailFakeDb.mails,
|
||||||
'mail-folders' : MailFakeDb.folders,
|
'mail-folders' : MailFakeDb.folders,
|
||||||
'mail-labels' : MailFakeDb.labels
|
'mail-labels' : MailFakeDb.labels,
|
||||||
|
'chat-contacts': ChatFakeDb.contacts,
|
||||||
|
'chat-chats' : ChatFakeDb.chats,
|
||||||
|
'chat-user' : ChatFakeDb.user,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
17
src/app/main/apps/chat/chat-start/chat-start.component.html
Normal file
17
src/app/main/apps/chat/chat-start/chat-start.component.html
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<div fxFlex fxLayout="column" fxLayoutAlign="center center">
|
||||||
|
|
||||||
|
<div class="big-circle mat-elevation-z1" fxLayout="column" fxLayoutAlign="center center">
|
||||||
|
|
||||||
|
<md-icon class="s-128">chat</md-icon>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<span class="app-title my-24">Chat App</span>
|
||||||
|
|
||||||
|
<span fxHide fxShow.gt-md class="app-message">Select contact to start the chat!..</span>
|
||||||
|
|
||||||
|
<button md-raised-button fxHide.gt-md class="" fuseMdSidenavToggler="chat-left-sidenav">
|
||||||
|
Select contact to start the chat!..
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</div>
|
30
src/app/main/apps/chat/chat-start/chat-start.component.scss
Normal file
30
src/app/main/apps/chat/chat-start/chat-start.component.scss
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
@import "src/app/core/scss/fuse";
|
||||||
|
|
||||||
|
:host {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(to bottom, rgba(255, 255, 255, 0.8) 0%, rgba(255, 255, 255, 0.6) 20%, rgba(255, 255, 255, 0.8));
|
||||||
|
|
||||||
|
.big-circle {
|
||||||
|
background: linear-gradient(to bottom, rgba(255, 255, 255, 0.8) 0%, rgba(255, 255, 255, 0.6) 20%, rgba(255, 255, 255, 0.8));
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 300px;
|
||||||
|
height: 300px;
|
||||||
|
line-height: 300px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
md-icon{
|
||||||
|
color: mat-color($accent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-title {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.secondary-text {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
}
|
19
src/app/main/apps/chat/chat-start/chat-start.component.ts
Normal file
19
src/app/main/apps/chat/chat-start/chat-start.component.ts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import {Component, OnInit} from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector : 'fuse-chat-start',
|
||||||
|
templateUrl: './chat-start.component.html',
|
||||||
|
styleUrls : ['./chat-start.component.scss']
|
||||||
|
})
|
||||||
|
export class ChatStartComponent implements OnInit
|
||||||
|
{
|
||||||
|
|
||||||
|
constructor()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
115
src/app/main/apps/chat/chat-view/chat-view.component.html
Normal file
115
src/app/main/apps/chat/chat-view/chat-view.component.html
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
<!-- CHAT -->
|
||||||
|
<div class="chat" fxFlex fxLayout="column">
|
||||||
|
|
||||||
|
<!-- CHAT TOOLBAR -->
|
||||||
|
<md-toolbar class="chat-toolbar">
|
||||||
|
|
||||||
|
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center">
|
||||||
|
|
||||||
|
<div fxLayout="row" fxLayoutAlign="start center">
|
||||||
|
|
||||||
|
<!-- RESPONSIVE CHATS BUTTON-->
|
||||||
|
<div md-button fxHide.gt-md class="responsive-chats-button mat-icon-button mr-16"
|
||||||
|
fuseMdSidenavToggler="chat-left-sidenav"
|
||||||
|
aria-label="chats button">
|
||||||
|
<md-icon class="s-36">chat</md-icon>
|
||||||
|
</div>
|
||||||
|
<!-- / RESPONSIVE CHATS BUTTON-->
|
||||||
|
|
||||||
|
<!-- CHAT CONTACT-->
|
||||||
|
<div class="chat-contact" fxLayout="row" fxLayoutAlign="start center"
|
||||||
|
fuseMdSidenavToggler="chat-right-sidenav" (click)="selectContact()">
|
||||||
|
|
||||||
|
<div class="avatar-wrapper">
|
||||||
|
|
||||||
|
<img [src]="contact.avatar"
|
||||||
|
class="avatar"
|
||||||
|
alt="{{contact.name}}"/>
|
||||||
|
|
||||||
|
<md-icon class="s-16 status"
|
||||||
|
[ngClass]="contact.status">
|
||||||
|
</md-icon>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="chat-contact-name">
|
||||||
|
{{contact.name}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- / CHAT CONTACT-->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<button md-button class="mat-icon-button" [mdMenuTriggerFor]="contactMenu"
|
||||||
|
aria-label="more">
|
||||||
|
<md-icon>more_vert</md-icon>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<md-menu #contactMenu="mdMenu">
|
||||||
|
<button md-menu-item fuseMdSidenavToggler="chat-right-sidenav" (click)="selectContact()">
|
||||||
|
Contact Info
|
||||||
|
</button>
|
||||||
|
</md-menu>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</md-toolbar>
|
||||||
|
<!-- / CHAT TOOLBAR -->
|
||||||
|
|
||||||
|
<!-- CHAT CONTENT -->
|
||||||
|
<div id="chat-content" fxFlex perfect-scrollbar>
|
||||||
|
|
||||||
|
<!-- CHAT MESSAGES -->
|
||||||
|
<div class="chat-messages">
|
||||||
|
|
||||||
|
<!-- MESSAGE -->
|
||||||
|
<div fxLayout="row" *ngFor="let message of dialog" class="message-row"
|
||||||
|
[ngClass]="{'user' :message.who === user.id}">
|
||||||
|
|
||||||
|
<img *ngIf="message.who === contact.id"
|
||||||
|
src="{{contact.avatar}}"
|
||||||
|
class="avatar"
|
||||||
|
alt="{{contact.name}}"/>
|
||||||
|
|
||||||
|
<img *ngIf="message.who ===user.id" class="avatar" src="{{user.avatar}}">
|
||||||
|
|
||||||
|
<div class="bubble">
|
||||||
|
<div class="message">{{message.message}}</div>
|
||||||
|
<div class="time secondary-text">{{message.time | date:'medium'}}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- / MESSAGE -->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- CHAT MESSAGES -->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- / CHAT CONTENT -->
|
||||||
|
|
||||||
|
<!-- CHAT FOOTER -->
|
||||||
|
<div class="chat-footer" fxLayout="row" fxLayoutAlign="center center">
|
||||||
|
|
||||||
|
<!-- REPLY FORM -->
|
||||||
|
<form #replyForm="ngForm"
|
||||||
|
(ngSubmit)="reply($event)"
|
||||||
|
(keyup.enter)="reply($event)"
|
||||||
|
fxFlex class="reply-form"
|
||||||
|
fxLayout="row"
|
||||||
|
fxLayoutAlign="start center">
|
||||||
|
|
||||||
|
<md-input-container class="" fxFlex floatPlaceholder="never">
|
||||||
|
<textarea mdInput #replyInput placeholder="Type and hit enter to send message"
|
||||||
|
ngModel name="message"></textarea>
|
||||||
|
</md-input-container>
|
||||||
|
|
||||||
|
<button md-fab class="" type="submit" aria-label="Send message">
|
||||||
|
<md-icon>send</md-icon>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
<!-- / REPLY FORM -->
|
||||||
|
</div>
|
||||||
|
<!-- / CHAT FOOTER-->
|
||||||
|
</div>
|
||||||
|
<!-- / CHAT -->
|
135
src/app/main/apps/chat/chat-view/chat-view.component.scss
Normal file
135
src/app/main/apps/chat/chat-view/chat-view.component.scss
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
:host {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(to bottom, rgba(255, 255, 255, 0.8) 0%, rgba(255, 255, 255, 0.6) 20%, rgba(255, 255, 255, 0.8));
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.chat {
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.chat-toolbar {
|
||||||
|
min-height: 64px;
|
||||||
|
background-color: #F3F4F5;
|
||||||
|
color: rgba(0, 0, 0, 0.87);
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, .08);
|
||||||
|
|
||||||
|
.responsive-chats-button {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-contact {
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-contact-name {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#chat-content {
|
||||||
|
background: transparent;
|
||||||
|
|
||||||
|
.message-row {
|
||||||
|
padding: 16px;
|
||||||
|
|
||||||
|
.bubble {
|
||||||
|
position: relative;
|
||||||
|
padding: 6px 7px 8px 9px;
|
||||||
|
background-color: #FFF;
|
||||||
|
box-shadow: 0 1px .5px rgba(0, 0, 0, .13);
|
||||||
|
border-radius: 6px;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAmCAMAAADp2asXAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAADGUExURQAAAP////b29vn5+f///wAAAP///wAAAAAAAP///9ra2v////j4+PHx8fv7++Hh4fHx8f////////////////39/QAAAP////////z8/P////39/f39/fz8/P////////////z8/P////////////z8/P////////////v7+/Hx8f///9bW1vz8/K2trf////39/f39/WJiYgAAAExMTFtbWwAAAN3d3cjIyPr6+vX19QAAAO7u7vz8/NTU1Ofn5zMzM////zGPlXsAAABBdFJOUwAcm/kREh4CCDWL1SneR6TfAQffhMYK/A5nRrLWfRc5DW2ih5f+19Kn+9v4g/1LCJuXHwQUKgahcXS6DNnlDMMKKzPoTgAAAKBJREFUKM+V08USwmAQA+C/0NIWd3d3d8/7vxTMcIPkQK7f7CG7s8bQAOY/SCuwFYQU1P+eiCqIK2gpWCmoCrAgoKQgJ8CHgIqAMjg0MxxSQ3DogEMWFBZtUPAHYGB1CyDQWE6AH7BrfXzlAxGAQhECTGAmwN1Okz0Gb/LW4fEItIfrOfNELMh3tck7u+PhcT2zQ7l77/K8iY8yJwV3BeYFqpc/uSyPGdAAAAAASUVORK5CYII=);
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: -11px;
|
||||||
|
bottom: 3px;
|
||||||
|
width: 12px;
|
||||||
|
height: 19px;
|
||||||
|
background-position: 50% 50%;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time {
|
||||||
|
font-size: 11px;
|
||||||
|
margin-top: 8px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.contact {
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
margin: 0 16px 0 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.user {
|
||||||
|
align-items: flex-end;
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
order: 2;
|
||||||
|
margin: 0 0 0 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bubble {
|
||||||
|
margin-left: auto;
|
||||||
|
background-color: #E8F5E9;
|
||||||
|
border: 1px solid #DFEBE0;
|
||||||
|
order: 1;
|
||||||
|
&:before {
|
||||||
|
right: -11px;
|
||||||
|
left: auto;
|
||||||
|
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAmCAMAAADp2asXAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAD2UExURQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGRsXAAAANzwzNPmxNrtyau5oIWRedDkwNntyczgwdfpyJ+/n97wzsLWtNjsytvwzczfvtPmxau6nNjqxtrtyio1KtzwzNjryAAAANzwzgAAANzwzK7Aor/Us9Lnw8vevAAAAMzevtbpxrvMrX+IdwAAAEROOi45Lr3MrZGjf9LoxX+MctnqydLkwhgYGMzfv9vuyQAAANzwzNvuy9zxy7vMu7XGqNvtzKKykwAAANruzKq6nLnMriQkGMXXuL3PsNjsySgzKAAAANLkw83fvd3vy9z4xtzwzRpFmIEAAABQdFJOUwAXChEGBAMBAgwhDvJ7k0YqMc0Zmwj6apf2kjU0+dkw/swh/CP9j2Wr2gndvaYeBRoxQg6gUPt/FaHJGdTj9A9k7XQLeE6iFcN12xkSt9r4NKizowAAAMFJREFUKM+V0sdywlAMBVDbMX7PQCihQ+iQ0HsJvfem/P/PwBIzugu0PXNnNNJVyPmhsIPhhoB2COwIGuLdhAcl3AhCBoBoHUC6BCBbA0C/EkBFB5D/FjxQwQYg1RI8UKINgDoSAPUlAPqUAMgfAEBfXsEDBV0+Hogi4Zhg4THj9YwHoqEBYOrgYTI3GVgMNn8r+Qq94k9yZNosW/3Hy9VuTjWfHkOX6367bGZUU7de66ieHZrO1OGg8Z1WTgYAFLgD5S1PCkzo1B0AAAAASUVORK5CYII=);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-footer {
|
||||||
|
min-height: 64px;
|
||||||
|
max-height: 96px;
|
||||||
|
background-color: #F3F4F5;
|
||||||
|
color: rgba(0, 0, 0, 0.87);
|
||||||
|
border-top: 1px solid rgba(0, 0, 0, .08);
|
||||||
|
padding: 8px 8px 8px 16px;
|
||||||
|
|
||||||
|
.reply-form {
|
||||||
|
|
||||||
|
md-input-container {
|
||||||
|
margin: 0;
|
||||||
|
padding-right: 16px;
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
overflow: auto;
|
||||||
|
max-height: 80px;
|
||||||
|
transition: height 200ms ease;
|
||||||
|
&.grow {
|
||||||
|
height: 80px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-errors-spacer {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-button {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
101
src/app/main/apps/chat/chat-view/chat-view.component.ts
Normal file
101
src/app/main/apps/chat/chat-view/chat-view.component.ts
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
import { AfterViewInit, Component, OnInit, ViewChild, ViewChildren } from '@angular/core';
|
||||||
|
import { ChatService } from '../chat.service';
|
||||||
|
import { NgForm } from '@angular/forms';
|
||||||
|
import { PerfectScrollbarDirective } from 'ngx-perfect-scrollbar';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector : 'fuse-chat-view',
|
||||||
|
templateUrl: './chat-view.component.html',
|
||||||
|
styleUrls : ['./chat-view.component.scss']
|
||||||
|
})
|
||||||
|
export class ChatViewComponent implements OnInit, AfterViewInit
|
||||||
|
{
|
||||||
|
user: any;
|
||||||
|
chat: any;
|
||||||
|
dialog: any;
|
||||||
|
contact: any;
|
||||||
|
replyInput: any;
|
||||||
|
selectedChat: any;
|
||||||
|
@ViewChild(PerfectScrollbarDirective) directiveScroll: PerfectScrollbarDirective;
|
||||||
|
@ViewChildren('replyInput') replyInputField;
|
||||||
|
@ViewChild('replyForm') replyForm: NgForm;
|
||||||
|
|
||||||
|
constructor(private chatService: ChatService)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit()
|
||||||
|
{
|
||||||
|
this.user = this.chatService.user;
|
||||||
|
this.chatService.onChatSelected
|
||||||
|
.subscribe(chatData => {
|
||||||
|
if ( chatData )
|
||||||
|
{
|
||||||
|
this.selectedChat = chatData;
|
||||||
|
this.contact = chatData.contact;
|
||||||
|
this.dialog = chatData.dialog;
|
||||||
|
this.readyToReply();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit()
|
||||||
|
{
|
||||||
|
this.replyInput = this.replyInputField.first.nativeElement;
|
||||||
|
this.readyToReply();
|
||||||
|
}
|
||||||
|
|
||||||
|
selectContact()
|
||||||
|
{
|
||||||
|
this.chatService.selectContact(this.contact);
|
||||||
|
}
|
||||||
|
|
||||||
|
readyToReply()
|
||||||
|
{
|
||||||
|
setTimeout(() => {
|
||||||
|
this.replyForm.reset();
|
||||||
|
this.focusReplyInput();
|
||||||
|
this.scrollToBottom();
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
focusReplyInput()
|
||||||
|
{
|
||||||
|
setTimeout(() => {
|
||||||
|
this.replyInput.focus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollToBottom(speed?: number)
|
||||||
|
{
|
||||||
|
speed = speed || 400;
|
||||||
|
if ( this.directiveScroll )
|
||||||
|
{
|
||||||
|
setTimeout(() => {
|
||||||
|
this.directiveScroll.scrollToBottom(0, speed);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
reply(event)
|
||||||
|
{
|
||||||
|
// Message
|
||||||
|
const message = {
|
||||||
|
who : this.user.id,
|
||||||
|
message: this.replyForm.form.value.message,
|
||||||
|
time : new Date().toISOString()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add the message to the chat
|
||||||
|
this.dialog.push(message);
|
||||||
|
|
||||||
|
// Update the server
|
||||||
|
this.chatService.updateDialog(this.selectedChat.chatId, this.dialog).then(response => {
|
||||||
|
this.readyToReply();
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,43 @@
|
||||||
<p>
|
<div class="page-layout carded fullwidth">
|
||||||
chat works!
|
|
||||||
</p>
|
<!-- TOP BACKGROUND -->
|
||||||
|
<div class="top-bg md-accent-bg"></div>
|
||||||
|
<!-- / TOP BACKGROUND -->
|
||||||
|
|
||||||
|
<!-- CENTER -->
|
||||||
|
<div class="center">
|
||||||
|
|
||||||
|
<!-- CONTENT CARD -->
|
||||||
|
<div class="content-card">
|
||||||
|
|
||||||
|
<md-sidenav-container>
|
||||||
|
|
||||||
|
<!-- LEFT SIDENAV -->
|
||||||
|
<md-sidenav class="sidenav mat-sidenav-opened" align="start" opened="true" mode="side"
|
||||||
|
fuseMdSidenavHelper="chat-left-sidenav" md-is-locked-open="gt-md">
|
||||||
|
<fuse-chat-left-sidenav></fuse-chat-left-sidenav>
|
||||||
|
</md-sidenav>
|
||||||
|
<!-- / LEFT SIDENAV -->
|
||||||
|
|
||||||
|
<!-- CONTENT -->
|
||||||
|
<fuse-chat-start *ngIf="!selectedChat"></fuse-chat-start>
|
||||||
|
|
||||||
|
<fuse-chat-view *ngIf="selectedChat"></fuse-chat-view>
|
||||||
|
<!-- / CONTENT -->
|
||||||
|
|
||||||
|
<!-- RIGHT SIDENAV -->
|
||||||
|
<md-sidenav class="sidenav mat-sidenav-opened" align="end" opened="false" mode="over"
|
||||||
|
fuseMdSidenavHelper="chat-right-sidenav">
|
||||||
|
<fuse-chat-right-sidenav></fuse-chat-right-sidenav>
|
||||||
|
</md-sidenav>
|
||||||
|
<!-- / RIGHT SIDENAV -->
|
||||||
|
|
||||||
|
</md-sidenav-container>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- / CONTENT CARD -->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- / CENTER -->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
:host {
|
||||||
|
height: 100% !important;
|
||||||
|
|
||||||
|
.center {
|
||||||
|
padding: 32px 32px 0 32px;
|
||||||
|
max-width: 1400px;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0 auto;
|
||||||
|
|
||||||
|
.content-card {
|
||||||
|
position: relative;
|
||||||
|
background: url('/assets/images/patterns/rain-grey.png') repeat;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.mat-sidenav-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: transparent;
|
||||||
|
|
||||||
|
md-sidenav {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 400px;
|
||||||
|
max-width: 90%;
|
||||||
|
box-shadow: 0 0 1px rgba(0, 0, 0, .37);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,15 +1,25 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||||
|
import { ChatService } from './chat.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector : 'fuse-chat',
|
selector : 'fuse-chat',
|
||||||
templateUrl: './chat.component.html',
|
templateUrl: './chat.component.html',
|
||||||
styleUrls : ['./chat.component.scss']
|
styleUrls : ['./chat.component.scss']
|
||||||
})
|
})
|
||||||
export class ChatComponent implements OnInit {
|
export class ChatComponent implements OnInit
|
||||||
|
{
|
||||||
|
selectedChat: any;
|
||||||
|
|
||||||
constructor() { }
|
constructor(private chatService: ChatService)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit()
|
||||||
|
{
|
||||||
|
this.chatService.onChatSelected
|
||||||
|
.subscribe(chatData => {
|
||||||
|
this.selectedChat = chatData;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,21 @@ import {NgModule} from '@angular/core';
|
||||||
import {SharedModule} from '../../../core/modules/shared.module';
|
import {SharedModule} from '../../../core/modules/shared.module';
|
||||||
import {RouterModule, Routes} from '@angular/router';
|
import {RouterModule, Routes} from '@angular/router';
|
||||||
import {ChatComponent} from './chat.component';
|
import {ChatComponent} from './chat.component';
|
||||||
|
import {ChatService} from './chat.service';
|
||||||
|
import { ChatViewComponent } from './chat-view/chat-view.component';
|
||||||
|
import { ChatStartComponent } from './chat-start/chat-start.component';
|
||||||
|
import {ChatsSidenavComponent} from './sidenavs/left/chats/chats.component';
|
||||||
|
import { UserSidenavComponent } from './sidenavs/left/user/user.component';
|
||||||
|
import { LeftSidenavComponent } from './sidenavs/left/left.component';
|
||||||
|
import { RightSidenavComponent } from './sidenavs/right/right.component';
|
||||||
|
import { ContactSidenavComponent } from './sidenavs/right/contact/contact.component';
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{
|
{
|
||||||
path: 'apps/chat', component: ChatComponent, children: []
|
path : 'apps/chat', component: ChatComponent, children: [],
|
||||||
|
resolve: {
|
||||||
|
chat: ChatService
|
||||||
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -15,7 +26,17 @@ const routes: Routes = [
|
||||||
RouterModule.forChild(routes)
|
RouterModule.forChild(routes)
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
ChatComponent
|
ChatComponent,
|
||||||
|
ChatViewComponent,
|
||||||
|
ChatStartComponent,
|
||||||
|
ChatsSidenavComponent,
|
||||||
|
UserSidenavComponent,
|
||||||
|
LeftSidenavComponent,
|
||||||
|
RightSidenavComponent,
|
||||||
|
ContactSidenavComponent
|
||||||
|
],
|
||||||
|
providers : [
|
||||||
|
ChatService
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class ChatModule
|
export class ChatModule
|
||||||
|
|
259
src/app/main/apps/chat/chat.service.ts
Normal file
259
src/app/main/apps/chat/chat.service.ts
Normal file
|
@ -0,0 +1,259 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
|
||||||
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
import { Http } from '@angular/http';
|
||||||
|
import { Subject } from 'rxjs/Subject';
|
||||||
|
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ChatService implements Resolve<any>
|
||||||
|
{
|
||||||
|
contacts: any[];
|
||||||
|
chats: any[];
|
||||||
|
user: any;
|
||||||
|
onChatSelected = new BehaviorSubject<any>(null);
|
||||||
|
onContactSelected = new BehaviorSubject<any>(null);
|
||||||
|
onChatsUpdated = new Subject<any>();
|
||||||
|
onUserUpdated = new Subject<any>();
|
||||||
|
onLeftSidenavViewChanged = new Subject<any>();
|
||||||
|
onRightSidenavViewChanged = new Subject<any>();
|
||||||
|
|
||||||
|
constructor(private http: Http)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get chat
|
||||||
|
* @param contactId
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
*/
|
||||||
|
getChat(contactId)
|
||||||
|
{
|
||||||
|
const chatItem = this.user.chatList.find((item) => {
|
||||||
|
return item.contactId === contactId;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create new chat, if it's not created yet.
|
||||||
|
*/
|
||||||
|
if ( !chatItem )
|
||||||
|
{
|
||||||
|
this.createNewChat(contactId).then((newChats) => {
|
||||||
|
this.getChat(contactId);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.http.get('api/chat-chats/' + chatItem.id)
|
||||||
|
.subscribe(response => {
|
||||||
|
const chat = response.json().data;
|
||||||
|
|
||||||
|
const chatContact = this.contacts.find((contact) => {
|
||||||
|
return contact.id === contactId;
|
||||||
|
});
|
||||||
|
|
||||||
|
const chatData = {
|
||||||
|
chatId : chat.id,
|
||||||
|
dialog : chat.dialog,
|
||||||
|
contact: chatContact
|
||||||
|
};
|
||||||
|
|
||||||
|
this.onChatSelected.next({...chatData});
|
||||||
|
|
||||||
|
}, reject);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create New Chat
|
||||||
|
* @param contactId
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
*/
|
||||||
|
createNewChat(contactId)
|
||||||
|
{
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
|
const contact = this.contacts.find((item) => {
|
||||||
|
return item.id === contactId;
|
||||||
|
});
|
||||||
|
|
||||||
|
const chatId = this.guidGenerator();
|
||||||
|
|
||||||
|
const chat = {
|
||||||
|
id : chatId,
|
||||||
|
dialog: []
|
||||||
|
};
|
||||||
|
|
||||||
|
const chatListItem = {
|
||||||
|
'id' : chatId,
|
||||||
|
'contactId' : contactId,
|
||||||
|
'unread' : null,
|
||||||
|
'lastMessageTime': '2017-02-18T10:30:18.931Z'
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add new chat list item to the user's chat list
|
||||||
|
*/
|
||||||
|
this.user.chatList.push(chatListItem);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Post the created chat
|
||||||
|
*/
|
||||||
|
this.http.post('api/chat-chats', {...chat})
|
||||||
|
.subscribe(response => {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Post the new the user data
|
||||||
|
*/
|
||||||
|
this.http.post('api/chat-user/' + this.user.id, this.user)
|
||||||
|
.subscribe(addedlistItem => {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the user data from server
|
||||||
|
*/
|
||||||
|
this.getUser().then(updatedUser => {
|
||||||
|
this.onUserUpdated.next(updatedUser);
|
||||||
|
resolve(updatedUser);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select Contact
|
||||||
|
* @param contact
|
||||||
|
*/
|
||||||
|
selectContact(contact)
|
||||||
|
{
|
||||||
|
this.onContactSelected.next(contact);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set user status
|
||||||
|
* @param status
|
||||||
|
*/
|
||||||
|
setUserStatus(status)
|
||||||
|
{
|
||||||
|
this.user.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update user data
|
||||||
|
* @param userData
|
||||||
|
*/
|
||||||
|
updateUserData(userData)
|
||||||
|
{
|
||||||
|
this.http.post('api/chat-user/' + this.user.id, userData)
|
||||||
|
.subscribe(response => {
|
||||||
|
this.user = userData;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the chat dialog
|
||||||
|
* @param chatId
|
||||||
|
* @param dialog
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
*/
|
||||||
|
updateDialog(chatId, dialog): Promise<any>
|
||||||
|
{
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
|
const newData = {
|
||||||
|
id : chatId,
|
||||||
|
dialog: dialog
|
||||||
|
};
|
||||||
|
|
||||||
|
this.http.post('api/chat-chats/' + chatId, newData)
|
||||||
|
.subscribe(updatedChat => {
|
||||||
|
resolve(updatedChat);
|
||||||
|
}, reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Mail App Main Resolver
|
||||||
|
* @param {ActivatedRouteSnapshot} route
|
||||||
|
* @param {RouterStateSnapshot} state
|
||||||
|
* @returns {Observable<any> | Promise<any> | any}
|
||||||
|
*/
|
||||||
|
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> | Promise<any> | any
|
||||||
|
{
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
Promise.all([
|
||||||
|
this.getContacts(),
|
||||||
|
this.getChats(),
|
||||||
|
this.getUser()
|
||||||
|
]).then(
|
||||||
|
([contacts, chats, user]) => {
|
||||||
|
this.contacts = contacts;
|
||||||
|
this.chats = chats;
|
||||||
|
this.user = user;
|
||||||
|
resolve();
|
||||||
|
},
|
||||||
|
reject
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Contacts
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
*/
|
||||||
|
getContacts(): Promise<any>
|
||||||
|
{
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.http.get('api/chat-contacts')
|
||||||
|
.subscribe(response => {
|
||||||
|
resolve(response.json().data);
|
||||||
|
}, reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Chats
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
*/
|
||||||
|
getChats(): Promise<any>
|
||||||
|
{
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.http.get('api/chat-chats')
|
||||||
|
.subscribe(response => {
|
||||||
|
resolve(response.json().data);
|
||||||
|
}, reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get User
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
*/
|
||||||
|
getUser(): Promise<any>
|
||||||
|
{
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.http.get('api/chat-user')
|
||||||
|
.subscribe(response => {
|
||||||
|
resolve(response.json().data[0]);
|
||||||
|
}, reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Random ID Generator
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
guidGenerator()
|
||||||
|
{
|
||||||
|
function S4()
|
||||||
|
{
|
||||||
|
return (((1 + Math.random()) * 0x10000) || 0).toString(16).substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (S4() + S4());
|
||||||
|
}
|
||||||
|
}
|
183
src/app/main/apps/chat/sidenavs/left/chats/chats.component.html
Normal file
183
src/app/main/apps/chat/sidenavs/left/chats/chats.component.html
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
<!-- SIDENAV HEADER -->
|
||||||
|
<div class="sidenav-header">
|
||||||
|
<!-- CHATS TOOLBAR -->
|
||||||
|
<md-toolbar>
|
||||||
|
|
||||||
|
<!-- TOOLBAR TOP -->
|
||||||
|
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center">
|
||||||
|
|
||||||
|
<!-- USER AVATAR WRAPPER -->
|
||||||
|
<div class="avatar-wrapper">
|
||||||
|
|
||||||
|
<!-- USER AVATAR -->
|
||||||
|
<img (click)="changeLeftSidenavView('user')"
|
||||||
|
src="{{user.avatar}}"
|
||||||
|
class="md-avatar avatar"
|
||||||
|
alt="{{user.name}}"/>
|
||||||
|
<!-- / USER AVATAR -->
|
||||||
|
|
||||||
|
<md-icon class="s-16 status" [ngClass]="user.status" [mdMenuTriggerFor]="userStatusMenu"></md-icon>
|
||||||
|
|
||||||
|
<!-- USER STATUS -->
|
||||||
|
<md-menu id="user-status-menu" #userStatusMenu="mdMenu">
|
||||||
|
|
||||||
|
<button md-menu-item (click)="setUserStatus('online')">
|
||||||
|
<div fxLayout="row" fxLayoutAlign="start center">
|
||||||
|
<md-icon class="s-16 status online"></md-icon>
|
||||||
|
<span>Online</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button md-menu-item (click)="setUserStatus('away')">
|
||||||
|
<div fxLayout="row" fxLayoutAlign="start center">
|
||||||
|
<md-icon class="s-16 status away"></md-icon>
|
||||||
|
<span>Away</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button md-menu-item (click)="setUserStatus('do-not-disturb')">
|
||||||
|
<div fxLayout="row" fxLayoutAlign="start center">
|
||||||
|
<md-icon class="s-16 status do-not-disturb"></md-icon>
|
||||||
|
<span>Do not disturb</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button md-menu-item (click)="setUserStatus('offline')">
|
||||||
|
<div fxLayout="row" fxLayoutAlign="start center">
|
||||||
|
<md-icon class="s-16 status offline"></md-icon>
|
||||||
|
<span>Offline</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
</md-menu>
|
||||||
|
<!-- / USER STATUS -->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- / USER AVATAR -->
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<button md-button class="mat-icon-button"
|
||||||
|
[mdMenuTriggerFor]="userMenu"
|
||||||
|
aria-label="more">
|
||||||
|
<md-icon>more_vert</md-icon>
|
||||||
|
</button>
|
||||||
|
<md-menu #userMenu="mdMenu">
|
||||||
|
<button md-menu-item (click)="changeLeftSidenavView('user')">
|
||||||
|
Profile
|
||||||
|
</button>
|
||||||
|
<button md-menu-item (click)="logout()">
|
||||||
|
Logout
|
||||||
|
</button>
|
||||||
|
</md-menu>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- / TOOLBAR TOP -->
|
||||||
|
|
||||||
|
<!-- TOOLBAR BOTTOM -->
|
||||||
|
<md-toolbar-row>
|
||||||
|
|
||||||
|
<!-- SEARCH -->
|
||||||
|
<div class="search-wrapper" fxFlex fxLayout="row" fxLayoutAlign="start center">
|
||||||
|
|
||||||
|
<div class="search" fxFlex fxLayout="row" fxLayoutAlign="start center">
|
||||||
|
|
||||||
|
<md-icon>search</md-icon>
|
||||||
|
|
||||||
|
<input [(ngModel)]="chatSearch.name" type="text" placeholder="Search or start new chat" fxFlex>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- / SEARCH -->
|
||||||
|
|
||||||
|
</md-toolbar-row>
|
||||||
|
<!-- / TOOLBAR BOTTOM -->
|
||||||
|
|
||||||
|
</md-toolbar>
|
||||||
|
<!-- / CHATS TOOLBAR -->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- / SIDENAV HEADER -->
|
||||||
|
|
||||||
|
<!-- SIDENAV CONTENT -->
|
||||||
|
<div class="sidenav-content" perfect-scrollbar fxFlex>
|
||||||
|
|
||||||
|
<!-- CHATS CONTENT -->
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<!-- CHATS LIST-->
|
||||||
|
<div class="chat-list" fxLayout="column">
|
||||||
|
|
||||||
|
<div md-subheader *ngIf="(user.chatList | filterBy: chatSearch).length > 0">
|
||||||
|
Chats
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button md-button class="contact"
|
||||||
|
*ngFor="let chat of user.chatList | filterBy: chatSearch"
|
||||||
|
(click)="getChat(chat.contactId)" ngClass="{'unread':contact.unread}">
|
||||||
|
|
||||||
|
<div fxLayout="row" fxLayoutAlign="start center">
|
||||||
|
|
||||||
|
<div class="avatar-wrapper" fxFlex="0 1 auto" fxLayoutAlign="center center">
|
||||||
|
<img [src]="contacts |getById:chat.contactId:'avatar'"
|
||||||
|
class="avatar"
|
||||||
|
alt="{{contacts |getById:chat.contactId:'name'}}"/>
|
||||||
|
<md-icon class="s-16 status" [ngClass]="contacts |getById:chat.contactId:'status'"></md-icon>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div fxLayout="row" fxFlex>
|
||||||
|
|
||||||
|
<div class="" fxFlex fxLayout="column" fxLayoutAlign="center start">
|
||||||
|
<div class="contact-name">{{contacts |getById:chat.contactId:'name'}}</div>
|
||||||
|
<p class="contact-last-message text-truncate">{{chat.lastMessage}}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div fxLayout="column" fxLayoutAlign="center end">
|
||||||
|
<div class="contact-last-message-time">
|
||||||
|
{{chat.lastMessageTime | date}}
|
||||||
|
</div>
|
||||||
|
<div *ngIf="chat.unread" class="unread-message-count">{{chat.unread}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- / CHATS LIST-->
|
||||||
|
|
||||||
|
<!-- CONTACTS LIST-->
|
||||||
|
<div class="contact-list" fxLayout="column">
|
||||||
|
|
||||||
|
<div md-subheader *ngIf="(contacts| filterBy: chatSearch).length > 0">
|
||||||
|
Contacts
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button md-button class="contact"
|
||||||
|
ng-show="chatSearch"
|
||||||
|
*ngFor="let contact of contacts| filterBy: chatSearch"
|
||||||
|
(click)="getChat(contact.id)">
|
||||||
|
|
||||||
|
<div fxLayout="row" fxLayoutAlign="start center">
|
||||||
|
<div class="avatar-wrapper" fxFlex="0 1 auto">
|
||||||
|
<img src="{{contact.avatar}}" class="md-avatar avatar" alt="{{contact.name}}"/>
|
||||||
|
<md-icon class="s-16 status" [ngClass]="contact.status"></md-icon>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="" fxLayout="column" fxLayoutAlign="center start">
|
||||||
|
<div class="contact-name">{{contact.name}}</div>
|
||||||
|
<p class="contact-mood">{{contact.mood}}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<!-- / CONTACTS LIST-->
|
||||||
|
|
||||||
|
<!-- NO RESULTS MESSAGE -->
|
||||||
|
<div *ngIf="(contacts| filterBy: chatSearch).length === 0" class="no-results-message">
|
||||||
|
No results..
|
||||||
|
</div>
|
||||||
|
<!-- NO RESULTS MESSAGE-->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- / CHATS CONTENT -->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- / SIDENAV CONTENT -->
|
110
src/app/main/apps/chat/sidenavs/left/chats/chats.component.scss
Normal file
110
src/app/main/apps/chat/sidenavs/left/chats/chats.component.scss
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
@import "src/app/core/scss/fuse";
|
||||||
|
|
||||||
|
:host {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.sidenav-header {
|
||||||
|
|
||||||
|
md-toolbar {
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, .08);
|
||||||
|
|
||||||
|
.avatar-wrapper {
|
||||||
|
|
||||||
|
.avatar, .status {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.search {
|
||||||
|
height: 36px;
|
||||||
|
line-height: 36px;
|
||||||
|
padding: 8px;
|
||||||
|
background: #FFFFFF;
|
||||||
|
font-size: 13px;
|
||||||
|
@include mat-elevation(1);
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
margin: 0;
|
||||||
|
color: rgba(0, 0, 0, 0.54);
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
padding-left: 12px;
|
||||||
|
height: 36px;
|
||||||
|
color: rgba(0, 0, 0, 0.54);
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidenav-content {
|
||||||
|
.contact-list, .chat-list {
|
||||||
|
|
||||||
|
.mat-subheader {
|
||||||
|
padding-left: 16px;
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 300;
|
||||||
|
height: 88px;
|
||||||
|
line-height: 88px;
|
||||||
|
color: mat-color($accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact {
|
||||||
|
white-space: normal;
|
||||||
|
text-align: left;
|
||||||
|
letter-spacing: .010em;
|
||||||
|
min-height: 88px;
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
|
||||||
|
padding: 16px;
|
||||||
|
font-weight: 400;
|
||||||
|
|
||||||
|
.avatar-wrapper {
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-name {
|
||||||
|
font-size: 16px;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-last-message {
|
||||||
|
line-height: 1.6em;
|
||||||
|
margin: 0;
|
||||||
|
font-weight: 500;
|
||||||
|
color: rgba(0, 0, 0, 0.54);
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-mood {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.unread-message-count {
|
||||||
|
border-radius: 50%;
|
||||||
|
text-align: center;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
line-height: 24px;
|
||||||
|
background-color: mat-color($accent);
|
||||||
|
color: map-get($accent, default-contrast);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-results-message {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 88px;
|
||||||
|
padding: 16px;
|
||||||
|
background: #FFFFFF;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { ChatService } from '../../../chat.service';
|
||||||
|
import { FuseMdSidenavHelperService } from '../../../../../../core/directives/md-sidenav-helper/md-sidenav-helper.service';
|
||||||
|
import { ObservableMedia } from '@angular/flex-layout';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector : 'fuse-chat-chats-sidenav',
|
||||||
|
templateUrl: './chats.component.html',
|
||||||
|
styleUrls : ['./chats.component.scss']
|
||||||
|
})
|
||||||
|
export class ChatsSidenavComponent implements OnInit
|
||||||
|
{
|
||||||
|
user: any;
|
||||||
|
chats: any[];
|
||||||
|
contacts: any[];
|
||||||
|
chatSearch: any;
|
||||||
|
|
||||||
|
constructor(private chatService: ChatService,
|
||||||
|
private fuseMdSidenavService: FuseMdSidenavHelperService,
|
||||||
|
public media: ObservableMedia)
|
||||||
|
{
|
||||||
|
this.chatSearch = {
|
||||||
|
name: ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit()
|
||||||
|
{
|
||||||
|
this.user = this.chatService.user;
|
||||||
|
this.chats = this.chatService.chats;
|
||||||
|
this.contacts = this.chatService.contacts;
|
||||||
|
|
||||||
|
this.chatService.onChatsUpdated.subscribe(updatedChats => {
|
||||||
|
this.chats = updatedChats;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.chatService.onUserUpdated.subscribe(updatedUser => {
|
||||||
|
this.user = updatedUser;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getChat(contact)
|
||||||
|
{
|
||||||
|
this.chatService.getChat(contact);
|
||||||
|
|
||||||
|
if ( !this.media.isActive('gt-md') )
|
||||||
|
{
|
||||||
|
this.fuseMdSidenavService.getSidenav('chat-left-sidenav').toggle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setUserStatus(status)
|
||||||
|
{
|
||||||
|
this.chatService.setUserStatus(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
changeLeftSidenavView(view)
|
||||||
|
{
|
||||||
|
this.chatService.onLeftSidenavViewChanged.next(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
logout()
|
||||||
|
{
|
||||||
|
console.info('logout triggered');
|
||||||
|
}
|
||||||
|
}
|
11
src/app/main/apps/chat/sidenavs/left/left.component.html
Normal file
11
src/app/main/apps/chat/sidenavs/left/left.component.html
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<div [ngSwitch]="view" class="views">
|
||||||
|
<fuse-chat-chats-sidenav class="view"
|
||||||
|
*ngSwitchCase="'chats'"
|
||||||
|
[@slideInRight]>
|
||||||
|
</fuse-chat-chats-sidenav>
|
||||||
|
|
||||||
|
<fuse-chat-user-sidenav class="view"
|
||||||
|
*ngSwitchCase="'user'"
|
||||||
|
[@slideInLeft]>
|
||||||
|
</fuse-chat-user-sidenav>
|
||||||
|
</div>
|
20
src/app/main/apps/chat/sidenavs/left/left.component.scss
Normal file
20
src/app/main/apps/chat/sidenavs/left/left.component.scss
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
:host {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.views {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.view {
|
||||||
|
position: absolute;
|
||||||
|
height: 100%;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
27
src/app/main/apps/chat/sidenavs/left/left.component.ts
Normal file
27
src/app/main/apps/chat/sidenavs/left/left.component.ts
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { Animations } from '../../../../../core/animations';
|
||||||
|
import { ChatService } from '../../chat.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector : 'fuse-chat-left-sidenav',
|
||||||
|
templateUrl: './left.component.html',
|
||||||
|
styleUrls : ['./left.component.scss'],
|
||||||
|
animations : [Animations.slideInLeft, Animations.slideInRight]
|
||||||
|
})
|
||||||
|
export class LeftSidenavComponent implements OnInit
|
||||||
|
{
|
||||||
|
view: string;
|
||||||
|
|
||||||
|
constructor(private chatService: ChatService)
|
||||||
|
{
|
||||||
|
this.view = 'chats';
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit()
|
||||||
|
{
|
||||||
|
this.chatService.onLeftSidenavViewChanged.subscribe(view => {
|
||||||
|
this.view = view;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
<!-- SIDENAV HEADER -->
|
||||||
|
<div class="sidenav-header">
|
||||||
|
|
||||||
|
<!-- USER TOOLBAR -->
|
||||||
|
<md-toolbar>
|
||||||
|
|
||||||
|
<!-- TOOLBAR TOP -->
|
||||||
|
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center">
|
||||||
|
|
||||||
|
<button md-button class="mat-icon-button" (click)="changeLeftSidenavView('chats')" aria-label="back">
|
||||||
|
<md-icon>arrow_back</md-icon>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- / TOOLBAR TOP -->
|
||||||
|
|
||||||
|
<!-- TOOLBAR BOTTOM -->
|
||||||
|
<md-toolbar-row class="toolbar-bottom" fxLayout="column" fxLayoutAlign="center center">
|
||||||
|
|
||||||
|
<img [src]="user.avatar" class="avatar user-avatar huge" alt="{{user.name}}"/>
|
||||||
|
|
||||||
|
<div class="user-name my-8">{{user.name}}</div>
|
||||||
|
|
||||||
|
</md-toolbar-row>
|
||||||
|
<!-- / TOOLBAR BOTTOM -->
|
||||||
|
|
||||||
|
</md-toolbar>
|
||||||
|
<!-- / USER TOOLBAR -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- SIDENAV CONTENT -->
|
||||||
|
<div class="sidenav-content p-16" perfect-scrollbar fxFlex>
|
||||||
|
|
||||||
|
<!-- USER MOOD -->
|
||||||
|
<md-card>
|
||||||
|
|
||||||
|
<form [formGroup]="userForm" fxLayout="column">
|
||||||
|
|
||||||
|
<md-input-container class="mb-24" fxFlex>
|
||||||
|
<textarea mdInput placeholder="Mood" name="mood"
|
||||||
|
formControlName="mood" rows="3"></textarea>
|
||||||
|
</md-input-container>
|
||||||
|
|
||||||
|
<md-radio-group formControlName="status" fxLayout="column">
|
||||||
|
|
||||||
|
<md-radio-button value="online" class="py-8">
|
||||||
|
<div fxLayout="row" fxLayoutAlign="start center">
|
||||||
|
<md-icon class="status online mr-8"></md-icon>
|
||||||
|
<span class="mat-h4 m-0">Online</span>
|
||||||
|
</div>
|
||||||
|
</md-radio-button>
|
||||||
|
|
||||||
|
<md-radio-button value="away" class="py-8">
|
||||||
|
<div fxLayout="row" fxLayoutAlign="start center">
|
||||||
|
<md-icon class="status away mr-8"></md-icon>
|
||||||
|
<span class="mat-h4 m-0">Away</span>
|
||||||
|
</div>
|
||||||
|
</md-radio-button>
|
||||||
|
|
||||||
|
<md-radio-button value="do-not-disturb" class="py-8">
|
||||||
|
<div fxLayout="row" fxLayoutAlign="start center">
|
||||||
|
<md-icon class="status do-not-disturb mr-8"></md-icon>
|
||||||
|
<span class="mat-h4 m-0">Do not disturb</span>
|
||||||
|
</div>
|
||||||
|
</md-radio-button>
|
||||||
|
|
||||||
|
<md-radio-button value="offline" class="py-8">
|
||||||
|
<div fxLayout="row" fxLayoutAlign="start center">
|
||||||
|
<md-icon class="status offline mr-8"></md-icon>
|
||||||
|
<span class="mat-h4 m-0">Offline</span>
|
||||||
|
</div>
|
||||||
|
</md-radio-button>
|
||||||
|
</md-radio-group>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</md-card>
|
||||||
|
<!-- / USER MOOD -->
|
||||||
|
</div>
|
|
@ -0,0 +1,21 @@
|
||||||
|
@import "src/app/core/scss/fuse";
|
||||||
|
|
||||||
|
:host {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
md-toolbar {
|
||||||
|
background-color: mat-color($accent);
|
||||||
|
color: map-get($accent, default-contrast);
|
||||||
|
|
||||||
|
.toolbar-bottom {
|
||||||
|
height: 240px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidenav-content{
|
||||||
|
background: whitesmoke;
|
||||||
|
}
|
||||||
|
}
|
47
src/app/main/apps/chat/sidenavs/left/user/user.component.ts
Normal file
47
src/app/main/apps/chat/sidenavs/left/user/user.component.ts
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||||
|
import { ChatService } from '../../../chat.service';
|
||||||
|
import { FormControl, FormGroup } from '@angular/forms';
|
||||||
|
import 'rxjs/Rx';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector : 'fuse-chat-user-sidenav',
|
||||||
|
templateUrl: './user.component.html',
|
||||||
|
styleUrls : ['./user.component.scss']
|
||||||
|
})
|
||||||
|
export class UserSidenavComponent implements OnInit, OnDestroy
|
||||||
|
{
|
||||||
|
user: any;
|
||||||
|
onFormChange: any;
|
||||||
|
userForm: FormGroup;
|
||||||
|
|
||||||
|
constructor(private chatService: ChatService)
|
||||||
|
{
|
||||||
|
this.user = this.chatService.user;
|
||||||
|
this.userForm = new FormGroup({
|
||||||
|
mood : new FormControl(this.user.mood),
|
||||||
|
status: new FormControl(this.user.status)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit()
|
||||||
|
{
|
||||||
|
this.onFormChange = this.userForm.valueChanges
|
||||||
|
.debounceTime(500)
|
||||||
|
.distinctUntilChanged()
|
||||||
|
.subscribe(data => {
|
||||||
|
this.user.mood = data.mood;
|
||||||
|
this.user.status = data.status;
|
||||||
|
this.chatService.updateUserData(this.user);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
changeLeftSidenavView(view)
|
||||||
|
{
|
||||||
|
this.chatService.onLeftSidenavViewChanged.next(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy()
|
||||||
|
{
|
||||||
|
this.onFormChange.unsubscribe();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
<!-- SIDENAV HEADER -->
|
||||||
|
<div class="sidenav-header" *ngIf="contact">
|
||||||
|
|
||||||
|
<!-- CONTACT TOOLBAR -->
|
||||||
|
<md-toolbar>
|
||||||
|
|
||||||
|
<!-- TOOLBAR TOP -->
|
||||||
|
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center">
|
||||||
|
|
||||||
|
<div>Contact Info</div>
|
||||||
|
|
||||||
|
<button md-button class="mat-icon-button" fuseMdSidenavToggler="chat-right-sidenav" aria-label="close">
|
||||||
|
<md-icon>close</md-icon>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- / TOOLBAR TOP -->
|
||||||
|
|
||||||
|
<!-- TOOLBAR BOTTOM -->
|
||||||
|
<md-toolbar-row class="toolbar-bottom" fxLayout="column" fxLayoutAlign="center center">
|
||||||
|
|
||||||
|
<img [src]="contact.avatar" class="avatar contact-avatar huge" alt="{{contact.name}}"/>
|
||||||
|
|
||||||
|
<div class="contact-name my-8">{{contact.name}}</div>
|
||||||
|
|
||||||
|
</md-toolbar-row>
|
||||||
|
<!-- / TOOLBAR BOTTOM -->
|
||||||
|
|
||||||
|
</md-toolbar>
|
||||||
|
<!-- / CONTACT TOOLBAR -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- SIDENAV CONTENT -->
|
||||||
|
<div class="sidenav-content p-16" perfect-scrollbar fxFlex *ngIf="contact">
|
||||||
|
|
||||||
|
<!-- CONTACT MOOD -->
|
||||||
|
<md-card>
|
||||||
|
|
||||||
|
<md-input-container fxFlex>
|
||||||
|
<textarea mdInput placeholder="Mood" name="mood"
|
||||||
|
[value]="contact.mood" rows="3" disabled>
|
||||||
|
</textarea>
|
||||||
|
</md-input-container>
|
||||||
|
|
||||||
|
</md-card>
|
||||||
|
<!-- / CONTACT MOOD -->
|
||||||
|
</div>
|
|
@ -0,0 +1,21 @@
|
||||||
|
@import "src/app/core/scss/fuse";
|
||||||
|
|
||||||
|
:host {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
md-toolbar {
|
||||||
|
background-color: mat-color($accent);
|
||||||
|
color: map-get($accent, default-contrast);
|
||||||
|
|
||||||
|
.toolbar-bottom {
|
||||||
|
height: 240px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidenav-content{
|
||||||
|
background: whitesmoke;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { ChatService } from '../../../chat.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector : 'fuse-chat-contact-sidenav',
|
||||||
|
templateUrl: './contact.component.html',
|
||||||
|
styleUrls : ['./contact.component.scss']
|
||||||
|
})
|
||||||
|
export class ContactSidenavComponent implements OnInit
|
||||||
|
{
|
||||||
|
contact: any;
|
||||||
|
|
||||||
|
constructor(private chatService: ChatService)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit()
|
||||||
|
{
|
||||||
|
this.chatService.onContactSelected.subscribe(contact => {
|
||||||
|
this.contact = contact;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
<div [ngSwitch]="view" class="views">
|
||||||
|
|
||||||
|
<fuse-chat-contact-sidenav class="view"
|
||||||
|
*ngSwitchCase="'contact'"
|
||||||
|
[@slideInRight]>
|
||||||
|
</fuse-chat-contact-sidenav>
|
||||||
|
|
||||||
|
</div>
|
20
src/app/main/apps/chat/sidenavs/right/right.component.scss
Normal file
20
src/app/main/apps/chat/sidenavs/right/right.component.scss
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
:host {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.views {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.view {
|
||||||
|
position: absolute;
|
||||||
|
height: 100%;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
27
src/app/main/apps/chat/sidenavs/right/right.component.ts
Normal file
27
src/app/main/apps/chat/sidenavs/right/right.component.ts
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { Animations } from '../../../../../core/animations';
|
||||||
|
import { ChatService } from '../../chat.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector : 'fuse-chat-right-sidenav',
|
||||||
|
templateUrl: './right.component.html',
|
||||||
|
styleUrls : ['./right.component.scss'],
|
||||||
|
animations : [Animations.slideInLeft, Animations.slideInRight]
|
||||||
|
})
|
||||||
|
export class RightSidenavComponent implements OnInit
|
||||||
|
{
|
||||||
|
view: string;
|
||||||
|
|
||||||
|
constructor(private chatService: ChatService)
|
||||||
|
{
|
||||||
|
this.view = 'contact';
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit()
|
||||||
|
{
|
||||||
|
this.chatService.onRightSidenavViewChanged.subscribe(view => {
|
||||||
|
this.view = view;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -26,7 +26,7 @@
|
||||||
"label-position": true,
|
"label-position": true,
|
||||||
"max-line-length": [
|
"max-line-length": [
|
||||||
true,
|
true,
|
||||||
120
|
180
|
||||||
],
|
],
|
||||||
"member-access": false,
|
"member-access": false,
|
||||||
"member-ordering": [
|
"member-ordering": [
|
||||||
|
|
Loading…
Reference in New Issue
Block a user