Compare commits

..

33 Commits

Author SHA1 Message Date
mustafahlvc
21c96c76da Merge remote-tracking branch 'origin/master' 2017-09-22 16:18:24 +03:00
mustafahlvc
5e2e2b7d53 Backdrop added to FuseNavBar for mobile 2017-09-22 16:18:05 +03:00
Sercan Yemen
dcff423943 Updated version to 1.1.0 since we have couple breaking changes! 2017-09-22 16:07:05 +03:00
Sercan Yemen
6747610771 Fixed: Fullwidth simple page layout doesn't scroll
+ Added: New logo to the various pages
+ Fixed: Mobile zoom is not disabled
+ Fixed: Profile timeline mobile order is not correct
+ Fixed: Quickpanel focusses to the form elements causing it to scroll on mobile devices when opened
+ Various demo page mobile fixes
2017-09-22 16:04:59 +03:00
Sercan Yemen
e6ee5d017e small tweaks and ng-* cleanups
+ Fixed: todo item action buttons shouldn't trigger "view todo" action
+ Fixed: contacts selected bar mobile issues
2017-09-22 15:02:07 +03:00
Sercan Yemen
cb2b544526 chat, todo & theme options tweaks 2017-09-22 12:11:21 +03:00
mustafahlvc
5ace09f782 Calendar, Contacts, Mail, Scrumboard apps responsive refinements,
+ temporary fix for md-sidenav-locked transition
2017-09-22 12:03:21 +03:00
Sercan Yemen
678dde8c0e calendar, mail and todo tweaks 2017-09-22 11:32:31 +03:00
Sercan Yemen
236cf1eb06 renamed the HMR starting scripts
+ modified the build scripts to use more memory. If you are having `out of memory` issues while building, use these scripts
2017-09-22 11:32:08 +03:00
Sercan Yemen
f4efbe07f7 Merge branch 'master' of https://github.com/withinpixels/fuse2 2017-09-22 09:23:38 +03:00
mustafahlvc
671287b55a Reverting the sidenav fixes.. 2017-09-21 19:03:19 +03:00
Sercan Yemen
19c85c964b updated the version number to 1.0.6 2017-09-21 15:54:25 +03:00
Sercan Yemen
e5cf4fdafb demo component and service page updates 2017-09-21 15:54:11 +03:00
Sercan Yemen
098dacf2a5 removed console warn 2017-09-21 15:13:27 +03:00
mustafahlvc
2f8539e987 Merge remote-tracking branch 'origin/master' 2017-09-21 15:05:36 +03:00
mustafahlvc
f688a58656 Animations enhanced for all apps and some pages. 2017-09-21 15:05:18 +03:00
Sercan Yemen
9cb8c0c96b Added a way to swap navigation model on the fly
Moved the navigation service to the app.module since we need it to be a singleton at all times
2017-09-21 14:56:08 +03:00
Sercan Yemen
05575d3f82 Fixed: Navigation model must be public 2017-09-21 14:08:37 +03:00
Sercan Yemen
b9198e3717 Entirely changed the navigation model structure (sorry!)
+ Fixed: Horizontal and Vertical navigation must be able to use the same model structure
+ Fixed: Collapsable nav item that has the active menu shouldn't be collapsed when other collapsables toggles
2017-09-21 12:08:52 +03:00
Sercan Yemen
769e67c2f3 Added HMR config. Use 'npm run hmr' for HMR enabled environment. This start script disables the sourcemaps to further increase the re-compile performance. If you need HMR with sourcemaps use 'npm run hmrs' 2017-09-21 10:58:19 +03:00
Sercan Yemen
32960abd7c fixed sidenav for fuse https://github.com/angular/material2/issues/7201 2017-09-20 17:38:14 +03:00
Sercan Yemen
126e32d9e7 updated Angular to 4.4.3 2017-09-20 10:06:43 +03:00
Sercan Yemen
d6d74cb998 small tweaks 2017-09-20 10:06:28 +03:00
Sercan Yemen
6d20c1d62d Custom perfect-scrollbar directive for better control (replaced the ngx-perfect-scrollbar with fuse-perfect-scrollbar) 2017-09-18 16:06:15 +03:00
Sercan Yemen
b55bce2de4 fixed: navigation collapsable issue on route change
fixed: footer stays on top of the navigation on mobile
2017-09-18 15:58:47 +03:00
Sercan Yemen
6f4dc36a3d locked dev dependency versions to prevent "npm update" errors! 2017-09-18 10:48:02 +03:00
Sercan Yemen
fe7e6d173b small tweaks and clean-ups 2017-09-18 10:47:35 +03:00
Sercan Yemen
b377d99c66 new fuse logo 2017-09-18 10:47:08 +03:00
Sercan Yemen
d4374e6df0 changed 'perfect-scrollbar' to 'perfectScrollbar' 2017-09-18 10:46:09 +03:00
Sercan Yemen
c74fad84b6 Merge branch 'master' of https://github.com/withinpixels/fuse2 2017-09-18 10:25:04 +03:00
mustafahlvc
e09ef05e02 (ngx-perfect-scroolbar) updated to v.4.6.2 2017-09-15 17:40:38 +03:00
Sercan Yemen
2c0fc76b8a meta tags and description for demo 2017-09-12 14:23:54 +03:00
Sercan Yemen
752660f5dc fix: theme options are not correctly shown on mobile 2017-09-12 10:25:11 +03:00
426 changed files with 32478 additions and 2125 deletions

View File

@@ -25,6 +25,7 @@
"environmentSource": "environments/environment.ts",
"environments": {
"dev": "environments/environment.ts",
"hmr": "environments/environment.hmr.ts",
"prod": "environments/environment.prod.ts"
}
}

2049
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,29 +1,32 @@
{
"name": "fuse2",
"version": "1.0.5",
"version": "1.1.0",
"license": "",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"start-hmr": "ng serve --hmr -e=hmr -sm=false",
"start-hmr-sourcemaps": "ng serve --hmr -e=hmr",
"build": "node --max_old_space_size=4096 ./node_modules/@angular/cli/bin/ng build",
"build-prod": "node --max_old_space_size=4096 ./node_modules/@angular/cli/bin/ng build --prod",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"dependencies": {
"@angular/animations": "4.3.5",
"@angular/animations": "4.4.3",
"@angular/cdk": "2.0.0-beta.10",
"@angular/common": "4.3.5",
"@angular/compiler": "4.3.5",
"@angular/core": "4.3.5",
"@angular/common": "4.4.3",
"@angular/compiler": "4.4.3",
"@angular/core": "4.4.3",
"@angular/flex-layout": "2.0.0-beta.9",
"@angular/forms": "4.3.5",
"@angular/http": "4.3.5",
"@angular/forms": "4.4.3",
"@angular/http": "4.4.3",
"@angular/material": "2.0.0-beta.10",
"@angular/platform-browser": "4.3.5",
"@angular/platform-browser-dynamic": "4.3.5",
"@angular/router": "4.3.5",
"@angular/platform-browser": "4.4.3",
"@angular/platform-browser-dynamic": "4.4.3",
"@angular/router": "4.4.3",
"@swimlane/ngx-charts": "6.0.2",
"@swimlane/ngx-datatable": "9.3.1",
"@swimlane/ngx-dnd": "3.0.0",
@@ -39,32 +42,34 @@
"moment": "2.18.1",
"ngx-color-picker": "4.3.1",
"ngx-cookie-service": "1.0.7",
"ngx-perfect-scrollbar": "4.5.6",
"ngx-perfect-scrollbar": "4.6.2",
"perfect-scrollbar": "0.8.1",
"rxjs": "5.4.3",
"web-animations-js": "2.3.1",
"zone.js": "0.8.17"
},
"devDependencies": {
"@angular/cli": "^1.3.2",
"@angular/compiler-cli": "4.3.5",
"@angular/language-service": "4.3.5",
"@ngtools/webpack": "^1.6.2",
"@types/jasmine": "^2.5.54",
"@types/jasminewd2": "^2.0.2",
"@types/node": "^6.0.88",
"codelyzer": "~3.0.1",
"jasmine-core": "~2.6.2",
"jasmine-spec-reporter": "~4.1.0",
"@angular/cli": "1.4.2",
"@angular/compiler-cli": "4.4.3",
"@angular/language-service": "4.4.3",
"@angularclass/hmr": "2.1.3",
"@ngtools/webpack": "1.7.1",
"@types/jasmine": "2.6.0",
"@types/jasminewd2": "2.0.2",
"@types/node": "6.0.88",
"codelyzer": "3.0.1",
"jasmine-core": "2.6.2",
"jasmine-spec-reporter": "4.1.0",
"karma": "1.7.1",
"karma-chrome-launcher": "~2.1.1",
"karma-cli": "~1.0.1",
"karma-coverage-istanbul-reporter": "^1.2.1",
"karma-jasmine": "~1.1.0",
"karma-jasmine-html-reporter": "^0.2.2",
"node-sass": "^4.5.3",
"protractor": "~5.1.2",
"ts-node": "~3.0.4",
"tslint": "~5.3.2",
"typescript": "~2.3.3"
"karma-chrome-launcher": "2.1.1",
"karma-cli": "1.0.1",
"karma-coverage-istanbul-reporter": "1.2.1",
"karma-jasmine": "1.1.0",
"karma-jasmine-html-reporter": "0.2.2",
"node-sass": "4.5.3",
"protractor": "5.1.2",
"ts-node": "3.0.4",
"tslint": "5.3.2",
"typescript": "2.3.3"
}
}

View File

@@ -4,19 +4,54 @@ import { HttpModule } from '@angular/http';
import { HttpClientModule } from '@angular/common/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { RouterModule, Routes } from '@angular/router';
import { InMemoryWebApiModule } from 'angular-in-memory-web-api';
import 'hammerjs';
import { SharedModule } from './core/modules/shared.module';
import { AppComponent } from './app.component';
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
import { ProjectModule } from './main/content/apps/dashboards/project/project.module';
import { FuseFakeDbService } from './fuse-fake-db/fuse-fake-db.service';
import { FuseMainModule } from './main/main.module';
import { PagesModule } from './main/content/pages/pages.module';
import { UIModule } from './main/content/ui/ui.module';
import { ComponentsModule } from './main/content/components/components.module';
import { FuseSplashScreenService } from './core/services/splash-screen.service';
import { FuseConfigService } from './core/services/config.service';
import { FuseSampleModule } from './main/content/sample/sample.module';
import { FuseNavigationService } from './core/components/navigation/navigation.service';
import { ComponentsThirdPartyModule } from './main/content/components-third-party/components-third-party.module';
import { ServicesModule } from './main/content/services/services.module';
const appRoutes: Routes = [
{
path : 'apps/mail',
loadChildren: './main/content/apps/mail/mail.module#FuseMailModule'
},
{
path : 'apps/chat',
loadChildren: './main/content/apps/chat/chat.module#FuseChatModule'
},
{
path : 'apps/calendar',
loadChildren: './main/content/apps/calendar/calendar.module#FuseCalendarModule'
},
{
path : 'apps/todo',
loadChildren: './main/content/apps/todo/todo.module#FuseTodoModule'
},
{
path : 'apps/file-manager',
loadChildren: './main/content/apps/file-manager/file-manager.module#FuseFileManagerModule'
},
{
path : 'apps/contacts',
loadChildren: './main/content/apps/contacts/contacts.module#FuseContactsModule'
},
{
path : 'apps/scrumboard',
loadChildren: './main/content/apps/scrumboard/scrumboard.module#FuseScrumboardModule'
},
{
path : '**',
redirectTo: 'sample'
redirectTo: 'apps/dashboards/project'
}
];
@@ -31,13 +66,23 @@ const appRoutes: Routes = [
BrowserAnimationsModule,
RouterModule.forRoot(appRoutes),
SharedModule,
PerfectScrollbarModule.forRoot(),
InMemoryWebApiModule.forRoot(FuseFakeDbService, {delay: 0}),
FuseMainModule,
FuseSampleModule
ProjectModule,
PagesModule,
UIModule,
ServicesModule,
ComponentsModule,
ComponentsThirdPartyModule
],
providers : [
FuseSplashScreenService,
FuseConfigService
FuseConfigService,
FuseNavigationService
],
bootstrap : [
AppComponent

View File

@@ -1,10 +1,56 @@
import { sequence, trigger, stagger, animate, style, group, query, transition, keyframes, animateChild, state } from '@angular/animations';
import { sequence, trigger, animate, style, group, query, transition, animateChild, state, animation, useAnimation, stagger } from '@angular/animations';
// const query = (s, a, o = {optional: true}) => q(s, a, o);
const customAnimation = animation([
style({
opacity : '{{opacity}}',
transform: 'scale({{scale}}) translate3d({{x}}, {{y}}, {{z}})'
}),
animate('{{duration}} {{delay}} cubic-bezier(0.0, 0.0, 0.2, 1)', style('*'))
], {
params: {
duration: '200ms',
delay : '0ms',
opacity : '0',
scale : '1',
x : '0',
y : '0',
z : '0'
}
});
export class Animations
{
public static fadeInOut = trigger('fadeInOut', [
export const fuseAnimations = [
trigger('animate', [transition('void => *', [useAnimation(customAnimation)])]),
trigger('animateStagger', [
state('50', style('*')),
state('100', style('*')),
state('200', style('*')),
transition('void => 50',
query('@*',
[
stagger('50ms', [
animateChild()
])
])),
transition('void => 100',
query('@*',
[
stagger('100ms', [
animateChild()
])
])),
transition('void => 200',
query('@*',
[
stagger('200ms', [
animateChild()
])
]))
]),
trigger('fadeInOut', [
state('0', style({
display: 'none',
opacity: 0
@@ -15,9 +61,9 @@ export class Animations
})),
transition('1 => 0', animate('300ms ease-out')),
transition('0 => 1', animate('300ms ease-in'))
]);
]),
public static slideInOut = trigger('slideInOut', [
trigger('slideInOut', [
state('0', style({
height : '0px',
display: 'none'
@@ -28,9 +74,9 @@ export class Animations
})),
transition('1 => 0', animate('300ms ease-out')),
transition('0 => 1', animate('300ms ease-in'))
]);
]),
public static slideInLeft = trigger('slideInLeft', [
trigger('slideInLeft', [
state('void', style({
transform: 'translateX(-100%)',
display : 'none'
@@ -41,9 +87,9 @@ export class Animations
})),
transition('void => *', animate('300ms')),
transition('* => void', animate('300ms'))
]);
]),
public static slideInRight = trigger('slideInRight', [
trigger('slideInRight', [
state('void', style({
transform: 'translateX(100%)',
display : 'none'
@@ -54,9 +100,9 @@ export class Animations
})),
transition('void => *', animate('300ms')),
transition('* => void', animate('300ms'))
]);
]),
public static slideInTop = trigger('slideInTop', [
trigger('slideInTop', [
state('void', style({
transform: 'translateY(-100%)',
display : 'none'
@@ -67,9 +113,9 @@ export class Animations
})),
transition('void => *', animate('300ms')),
transition('* => void', animate('300ms'))
]);
]),
public static slideInBottom = trigger('slideInBottom', [
trigger('slideInBottom', [
state('void',
style({
transform: 'translateY(100%)',
@@ -81,9 +127,9 @@ export class Animations
})),
transition('void => *', animate('300ms')),
transition('* => void', animate('300ms'))
]);
]),
public static routerTransitionLeft = trigger('routerTransitionLeft', [
trigger('routerTransitionLeft', [
transition('* => *', [
query('fuse-content > :enter, fuse-content > :leave', [
@@ -108,7 +154,7 @@ export class Animations
transform: 'translateX(0)',
opacity : 1
}),
animate('400ms cubic-bezier(0.250, 0.460, 0.450, 0.940)',
animate('600ms cubic-bezier(0.0, 0.0, 0.2, 1)',
style({
transform: 'translateX(-100%)',
opacity : 0
@@ -116,7 +162,7 @@ export class Animations
], {optional: true}),
query('fuse-content > :enter', [
style({transform: 'translateX(100%)'}),
animate('400ms cubic-bezier(0.250, 0.460, 0.450, 0.940)',
animate('600ms cubic-bezier(0.0, 0.0, 0.2, 1)',
style({
transform: 'translateX(0%)',
opacity : 1
@@ -127,9 +173,9 @@ export class Animations
query('fuse-content > :enter', animateChild(), {optional: true})
])
])
]);
]),
public static routerTransitionRight = trigger('routerTransitionRight', [
trigger('routerTransitionRight', [
transition('* => *', [
query('fuse-content > :enter, fuse-content > :leave', [
@@ -154,7 +200,7 @@ export class Animations
transform: 'translateX(0)',
opacity : 1
}),
animate('400ms cubic-bezier(0.250, 0.460, 0.450, 0.940)',
animate('600ms cubic-bezier(0.0, 0.0, 0.2, 1)',
style({
transform: 'translateX(100%)',
opacity : 0
@@ -162,7 +208,7 @@ export class Animations
], {optional: true}),
query('fuse-content > :enter', [
style({transform: 'translateX(-100%)'}),
animate('400ms cubic-bezier(0.250, 0.460, 0.450, 0.940)',
animate('600ms cubic-bezier(0.0, 0.0, 0.2, 1)',
style({
transform: 'translateX(0%)',
opacity : 1
@@ -173,9 +219,9 @@ export class Animations
query('fuse-content > :enter', animateChild(), {optional: true})
])
])
]);
]),
public static routerTransitionUp = trigger('routerTransitionUp', [
trigger('routerTransitionUp', [
transition('* => *', [
query('fuse-content > :enter, fuse-content > :leave', [
@@ -193,35 +239,33 @@ export class Animations
opacity : 0
})
], {optional: true}),
sequence([
group([
query('fuse-content > :leave', [
group([
query('fuse-content > :leave', [
style({
transform: 'translateY(0)',
opacity : 1
}),
animate('600ms cubic-bezier(0.0, 0.0, 0.2, 1)',
style({
transform: 'translateY(0)',
transform: 'translateY(-100%)',
opacity : 0
}))
], {optional: true}),
query('fuse-content > :enter', [
style({transform: 'translateY(100%)'}),
animate('600ms cubic-bezier(0.0, 0.0, 0.2, 1)',
style({
transform: 'translateY(0%)',
opacity : 1
}),
animate('400ms cubic-bezier(0.250, 0.460, 0.450, 0.940)',
style({
transform: 'translateY(-100%)',
opacity : 0
}))
], {optional: true}),
query('fuse-content > :enter', [
style({transform: 'translateY(100%)'}),
animate('400ms cubic-bezier(0.250, 0.460, 0.450, 0.940)',
style({
transform: 'translateY(0%)',
opacity : 1
}))
], {optional: true})
]),
query('fuse-content > :leave', animateChild(), {optional: true}),
query('fuse-content > :enter', animateChild(), {optional: true})
])
}))
], {optional: true})
]),
query('fuse-content > :leave', animateChild(), {optional: true}),
query('fuse-content > :enter', animateChild(), {optional: true})
])
]);
]),
public static routerTransitionDown = trigger('routerTransitionDown', [
trigger('routerTransitionDown', [
transition('* => *', [
query('fuse-content > :enter, fuse-content > :leave', [
@@ -246,7 +290,7 @@ export class Animations
transform: 'translateY(0)',
opacity : 1
}),
animate('400ms cubic-bezier(0.250, 0.460, 0.450, 0.940)',
animate('600ms cubic-bezier(0.0, 0.0, 0.2, 1)',
style({
transform: 'translateY(100%)',
opacity : 0
@@ -254,7 +298,7 @@ export class Animations
], {optional: true}),
query('fuse-content > :enter', [
style({transform: 'translateY(-100%)'}),
animate('400ms cubic-bezier(0.250, 0.460, 0.450, 0.940)',
animate('600ms cubic-bezier(0.0, 0.0, 0.2, 1)',
style({
transform: 'translateY(0%)',
opacity : 1
@@ -265,11 +309,11 @@ export class Animations
query('fuse-content > :enter', animateChild(), {optional: true})
])
])
]);
]),
public static routerTransitionFade = trigger('routerTransitionFade', [
trigger('routerTransitionFade', [
transition('* => *', [
transition('* => *', group([
query('fuse-content > :enter, fuse-content > :leave ', [
style({
@@ -280,33 +324,32 @@ export class Animations
right : 0
})
], {optional: true}),
query('fuse-content > :enter', [
style({
opacity: 0
})
], {optional: true}),
// sequence([
query('fuse-content > :leave', [
style({
opacity: 1
}),
animate('300ms cubic-bezier(0.250, 0.460, 0.450, 0.940)',
style({
opacity: 0
}))
], {optional: true}),
query('fuse-content > :enter', [
query('fuse-content > :leave', [
style({
opacity: 1
}),
animate('300ms cubic-bezier(0.0, 0.0, 0.2, 1)',
style({
opacity: 0
}),
animate('300ms cubic-bezier(0.250, 0.460, 0.450, 0.940)',
style({
opacity: 1
}))
], {optional: true}),
// ]),
}))
], {optional: true}),
query('fuse-content > :enter', [
style({
opacity: 0
}),
animate('300ms cubic-bezier(0.0, 0.0, 0.2, 1)',
style({
opacity: 1
}))
], {optional: true}),
query('fuse-content > :enter', animateChild(), {optional: true}),
query('fuse-content > :leave', animateChild(), {optional: true})
])
]);
}
]))
])
];

View File

@@ -45,7 +45,7 @@
<div fxLayout="row" fxLayoutWrap
fxLayoutAlign="start start"
class="colors" perfect-scrollbar>
class="colors" fusePerfectScrollbar>
<div class="color"
[ngClass]="'md-'+color.key+'-bg'"
*ngFor="let color of (colors | keys)"
@@ -63,7 +63,7 @@
[@slideInRight]>
<div fxLayout="row" fxLayoutWrap
fxLayoutAlign="start start"
class="colors" perfect-scrollbar>
class="colors" fusePerfectScrollbar>
<div class="color"
*ngFor="let hue of hues"
[fxHide]="selectedPalette === 'white' && hue !== '500'|| selectedPalette === 'black' && hue !== '500'"

View File

@@ -1,12 +1,12 @@
import { Component, EventEmitter, Input, OnChanges, OnInit, Output, ViewEncapsulation } from '@angular/core';
import { MatColors } from '../../matColors';
import { Animations } from '../../animations';
import { fuseAnimations } from '../../animations';
@Component({
selector : 'fuse-material-color-picker',
templateUrl : './material-color-picker.component.html',
styleUrls : ['./material-color-picker.component.scss'],
animations : [Animations.slideInLeft, Animations.slideInRight],
animations : fuseAnimations,
encapsulation: ViewEncapsulation.None
})
export class FuseMaterialColorPickerComponent implements OnInit, OnChanges

View File

@@ -9,9 +9,8 @@
<div class="{{fuseSettings.colorClasses.navbar}}">
<ng-container *ngFor="let item of item.children">
<fuse-nav-horizontal-item *ngIf="item.type=='nav-item'" [item]="item"></fuse-nav-horizontal-item>
<fuse-nav-horizontal-collapse *ngIf="item.type=='nav-collapse'"
[item]="item"></fuse-nav-horizontal-collapse>
<fuse-nav-horizontal-item *ngIf="item.type=='item'" [item]="item"></fuse-nav-horizontal-item>
<fuse-nav-horizontal-collapse *ngIf="item.type=='collapse'" [item]="item"></fuse-nav-horizontal-collapse>
</ng-container>
</div>

View File

@@ -1,5 +1,5 @@
import { Component, HostBinding, HostListener, Input, OnDestroy } from '@angular/core';
import { Animations } from '../../../../animations';
import { fuseAnimations } from '../../../../animations';
import { FuseConfigService } from '../../../../services/config.service';
import { Subscription } from 'rxjs/Subscription';
@@ -7,7 +7,7 @@ import { Subscription } from 'rxjs/Subscription';
selector : 'fuse-nav-horizontal-collapse',
templateUrl: './nav-horizontal-collapse.component.html',
styleUrls : ['./nav-horizontal-collapse.component.scss'],
animations : [Animations.slideInOut]
animations : fuseAnimations
})
export class FuseNavHorizontalCollapseComponent implements OnDestroy
{

View File

@@ -1,27 +1,32 @@
<div id="main-navigation" class="nav" [ngClass]="{'horizontal':layout === 'horizontal'}">
<div id="main-navigation" class="nav"
[ngClass]="{'horizontal':layout === 'horizontal', 'vertical':layout === 'vertical'}">
<!-- Vertical Navigation Layout -->
<ng-container *ngIf="layout === 'vertical'">
<ng-container *ngFor="let item of verticalNavigation">
<ng-container *ngFor="let item of navigationModel">
<fuse-nav-vertical-subheader *ngIf="item.type=='subheader'" [item]="item"></fuse-nav-vertical-subheader>
<fuse-nav-vertical-item *ngIf="item.type=='nav-item'" [item]="item"></fuse-nav-vertical-item>
<fuse-nav-vertical-collapse *ngIf="item.type=='nav-collapse'" [item]="item"></fuse-nav-vertical-collapse>
<fuse-nav-vertical-group *ngIf="item.type=='group'" [item]="item"></fuse-nav-vertical-group>
<fuse-nav-vertical-collapse *ngIf="item.type=='collapse'" [item]="item"></fuse-nav-vertical-collapse>
<fuse-nav-vertical-item *ngIf="item.type=='item'" [item]="item"></fuse-nav-vertical-item>
</ng-container>
</ng-container>
<!-- / Vertical Navigation Layout -->
<!-- Horizontal Navigation Layout -->
<ng-container *ngIf="layout === 'horizontal'">
<ng-container *ngFor="let item of horizontalNavigation">
<ng-container *ngFor="let item of navigationModel">
<fuse-nav-horizontal-collapse *ngIf="item.type=='group'" [item]="item"></fuse-nav-horizontal-collapse>
<fuse-nav-horizontal-collapse *ngIf="item.type=='collapse'" [item]="item"></fuse-nav-horizontal-collapse>
<fuse-nav-horizontal-item *ngIf="item.type=='nav-item'" [item]="item"></fuse-nav-horizontal-item>
<fuse-nav-horizontal-collapse *ngIf="item.type=='nav-collapse'"
[item]="item"></fuse-nav-horizontal-collapse>
</ng-container>
</ng-container>
<!-- / Horizontal Navigation Layout -->
</div>

View File

@@ -1,5 +1,6 @@
import { Component, Input, ViewEncapsulation } from '@angular/core';
import { Component, Input, OnDestroy, ViewEncapsulation } from '@angular/core';
import { FuseNavigationService } from './navigation.service';
import { Subscription } from 'rxjs/Subscription';
@Component({
selector : 'fuse-navigation',
@@ -7,17 +8,26 @@ import { FuseNavigationService } from './navigation.service';
styleUrls : ['./navigation.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class FuseNavigationComponent
export class FuseNavigationComponent implements OnDestroy
{
verticalNavigation: any[];
horizontalNavigation: any[];
navigationModel: any[];
navigationModelChangeSubscription: Subscription;
@Input('layout') layout = 'vertical';
constructor(private navigationService: FuseNavigationService)
constructor(private fuseNavigationService: FuseNavigationService)
{
this.verticalNavigation = navigationService.getNavigation('verticalNavItems');
this.horizontalNavigation = navigationService.getNavigation('horizontalNavItems');
this.navigationModelChangeSubscription =
this.fuseNavigationService.onNavigationModelChange
.subscribe((navigationModel) => {
this.navigationModel = navigationModel;
});
}
ngOnDestroy()
{
console.warn('destroyed');
this.navigationModelChangeSubscription.unsubscribe();
}
}

View File

@@ -4,7 +4,7 @@ import { RouterModule } from '@angular/router';
import { FuseNavigationComponent } from './navigation.component';
import { FuseNavVerticalItemComponent } from './vertical/nav-item/nav-vertical-item.component';
import { FuseNavVerticalCollapseComponent } from './vertical/nav-collapse/nav-vertical-collapse.component';
import { FuseNavVerticalSubheaderComponent } from './vertical/nav-subheader/nav-vertical-subheader.component';
import { FuseNavVerticalGroupComponent } from './vertical/nav-group/nav-vertical-group.component';
import { FuseNavHorizontalItemComponent } from './horizontal/nav-item/nav-horizontal-item.component';
import { FuseNavHorizontalCollapseComponent } from './horizontal/nav-collapse/nav-horizontal-collapse.component';
@@ -18,7 +18,7 @@ import { FuseNavHorizontalCollapseComponent } from './horizontal/nav-collapse/na
],
declarations: [
FuseNavigationComponent,
FuseNavVerticalSubheaderComponent,
FuseNavVerticalGroupComponent,
FuseNavVerticalItemComponent,
FuseNavVerticalCollapseComponent,
FuseNavHorizontalItemComponent,

View File

@@ -1,25 +1,43 @@
import { EventEmitter, Injectable } from '@angular/core';
import { FuseNavigation } from '../../../navigation.model';
import { NavigationModel } from '../../../navigation.model';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
@Injectable()
export class FuseNavigationService
{
onNavCollapseToggled = new EventEmitter<any>();
navigation: FuseNavigation;
onNavigationModelChange: BehaviorSubject<any> = new BehaviorSubject({});
navigationModel: NavigationModel;
flatNavigation: any[] = [];
constructor()
{
this.navigation = new FuseNavigation();
this.navigationModel = new NavigationModel();
this.onNavigationModelChange.next(this.navigationModel.model);
}
/**
* Get navigation array
* Get navigation model
* @returns {any[]}
*/
getNavigation(item)
getNavigationModel()
{
return this.navigation[item];
return this.navigationModel.model;
}
/**
* Set the navigation model
* @param model
*/
setNavigationModel(model)
{
// console.log(model);
this.navigationModel = model;
console.log(this.navigationModel);
this.onNavigationModelChange.next(this.navigationModel.model);
}
/**
@@ -31,7 +49,7 @@ export class FuseNavigationService
{
if ( !navigationItems )
{
navigationItems = this.navigation;
navigationItems = this.navigationModel.model;
}
for ( const navItem of navigationItems )
@@ -41,7 +59,7 @@ export class FuseNavigationService
continue;
}
if ( navItem.type === 'nav-item' )
if ( navItem.type === 'item' )
{
this.flatNavigation.push({
title: navItem.title,
@@ -53,7 +71,7 @@ export class FuseNavigationService
continue;
}
if ( navItem.type === 'nav-collapse' )
if ( navItem.type === 'collapse' || navItem.type === 'group' )
{
this.getFlatNavigation(navItem.children);
}

View File

@@ -5,7 +5,7 @@
</a>
<div class="children" [@slideInOut]="isOpen">
<ng-container *ngFor="let item of item.children">
<fuse-nav-vertical-item *ngIf="item.type=='nav-item'" [item]="item"></fuse-nav-vertical-item>
<fuse-nav-vertical-collapse *ngIf="item.type=='nav-collapse'" [item]="item"></fuse-nav-vertical-collapse>
<fuse-nav-vertical-item *ngIf="item.type=='item'" [item]="item"></fuse-nav-vertical-item>
<fuse-nav-vertical-collapse *ngIf="item.type=='collapse'" [item]="item"></fuse-nav-vertical-collapse>
</ng-container>
</div>

View File

@@ -1,13 +1,13 @@
import { Component, HostBinding, Input, OnInit } from '@angular/core';
import { FuseNavigationService } from '../../navigation.service';
import { NavigationEnd, Router } from '@angular/router';
import { Animations } from '../../../../animations';
import { fuseAnimations } from '../../../../animations';
@Component({
selector : 'fuse-nav-vertical-collapse',
templateUrl: './nav-vertical-collapse.component.html',
styleUrls : ['./nav-vertical-collapse.component.scss'],
animations : [Animations.slideInOut]
animations : fuseAnimations
})
export class FuseNavVerticalCollapseComponent implements OnInit
{
@@ -15,21 +15,20 @@ export class FuseNavVerticalCollapseComponent implements OnInit
@HostBinding('class') classes = 'nav-collapse nav-item';
@HostBinding('class.open') public isOpen = false;
constructor(private navigationService: FuseNavigationService, private router: Router)
constructor(
private navigationService: FuseNavigationService,
private router: Router
)
{
/**
* When navigation changed
*/
// Listen for route changes
router.events.subscribe(
(event) => {
if ( event instanceof NavigationEnd )
{
/**
* Check if the url is child of the collapse
*/
// Check if the url can be found in
// one of the children of this item
if ( this.isUrlInChildren(this.item, event.urlAfterRedirects) )
{
// console.log(this.item);
this.expand();
}
else
@@ -40,47 +39,53 @@ export class FuseNavVerticalCollapseComponent implements OnInit
}
);
/**
* Whenever a navigation collapse item toggled
*/
this.navigationService.onNavCollapseToggled.subscribe(
(clickedItem) => {
if ( clickedItem.children )
{
/**
* if clicked collapse is child of this collapse
* return
*/
if ( this.item.children.indexOf(clickedItem) !== -1 )
// Listen for collapsing of any navigation item
this.navigationService.onNavCollapseToggled
.subscribe(
(clickedItem) => {
if ( clickedItem.children )
{
return;
}
/**
* If collapsed item is not related with this collapse
* collapse
*/
if ( this.item !== clickedItem )
{
this.collapse();
// Check if the clicked item is one
// of the children of this item
if ( this.isChildrenOf(this.item, clickedItem) )
{
return;
}
// Check if the url can be found in
// one of the children of this item
if ( this.isUrlInChildren(this.item, this.router.url) )
{
return;
}
// If the clicked item is not this item, collapse...
if ( this.item !== clickedItem )
{
this.collapse();
}
}
}
}
);
);
}
/**
* Toggle Collapse
* Toggle collapse
*
* @param ev
*/
toggleOpen(ev)
{
ev.preventDefault();
this.isOpen = !this.isOpen;
// Navigation collapse toggled...
this.navigationService.onNavCollapseToggled.emit(this.item);
}
/**
* Expand
* Expand the collapsable navigation
*/
expand()
{
@@ -88,11 +93,12 @@ export class FuseNavVerticalCollapseComponent implements OnInit
{
return;
}
this.isOpen = true;
}
/**
* Collapse
* Collapse the collapsable navigation
*/
collapse()
{
@@ -104,29 +110,60 @@ export class FuseNavVerticalCollapseComponent implements OnInit
}
/**
* Checking the url is in children
* @param arr
* @param url
* @returns {any}
* Check if the given parent has the
* given item in one of its children
*
* @param parent
* @param item
* @return {any}
*/
isUrlInChildren(arr, url)
isChildrenOf(parent, item)
{
if ( !arr.children )
if ( !parent.children )
{
return false;
}
for ( let i = 0; i < arr.children.length; i++ )
if ( parent.children.indexOf(item) !== -1 )
{
if ( arr.children[i].children )
return true;
}
for ( const children of parent.children )
{
if ( children.children )
{
if ( this.isUrlInChildren(arr.children[i], url) )
return this.isChildrenOf(children, item);
}
}
}
/**
* Check if the given url can be found
* in one of the given parent's children
*
* @param parent
* @param url
* @returns {any}
*/
isUrlInChildren(parent, url)
{
if ( !parent.children )
{
return false;
}
for ( let i = 0; i < parent.children.length; i++ )
{
if ( parent.children[i].children )
{
if ( this.isUrlInChildren(parent.children[i], url) )
{
return true;
}
}
if ( arr.children[i].url === url )
if ( parent.children[i].url === url )
{
return true;
}
@@ -135,11 +172,6 @@ export class FuseNavVerticalCollapseComponent implements OnInit
return false;
}
public isCollapsed(): boolean
{
return this.isOpen;
}
ngOnInit()
{
}

View File

@@ -0,0 +1,10 @@
<div class="group-title">
<span class="hint-text">{{ item.title }}</span>
</div>
<div class="group-items">
<ng-container *ngFor="let item of item.children">
<fuse-nav-vertical-group *ngIf="item.type=='group'" [item]="item"></fuse-nav-vertical-group>
<fuse-nav-vertical-collapse *ngIf="item.type=='collapse'" [item]="item"></fuse-nav-vertical-collapse>
<fuse-nav-vertical-item *ngIf="item.type=='item'" [item]="item"></fuse-nav-vertical-item>
</ng-container>
</div>

View File

@@ -0,0 +1,23 @@
:host {
.folded:not(.folded-open) & {
> .group-title {
align-items: center;
> span {
opacity: 0;
transition: opacity 200ms ease;
}
&:before {
content: '';
display: block;
position: absolute;
min-width: 1.6rem;
border-top: 2px solid;
opacity: 0.2;
}
}
}
}

View File

@@ -0,0 +1,21 @@
import { Component, HostBinding, Input, OnInit } from '@angular/core';
@Component({
selector : 'fuse-nav-vertical-group',
templateUrl: './nav-vertical-group.component.html',
styleUrls : ['./nav-vertical-group.component.scss']
})
export class FuseNavVerticalGroupComponent implements OnInit
{
@HostBinding('class') classes = 'nav-group';
@Input() item: any;
constructor()
{
}
ngOnInit()
{
}
}

View File

@@ -1 +0,0 @@
<span class="hint-text">{{ item.title }}</span>

View File

@@ -1,20 +0,0 @@
:host {
.folded:not(.folded-open) & {
&:before {
content: '';
display: block;
position: absolute;
min-width: 1.6rem;
border-top: 2px solid;
opacity: 0.2;
}
> span {
opacity: 0;
transition: opacity 200ms ease;
}
}
}

View File

@@ -1,21 +0,0 @@
import { Component, HostBinding, Input, OnInit } from '@angular/core';
@Component({
selector : 'fuse-nav-vertical-subheader',
templateUrl: './nav-vertical-subheader.component.html',
styleUrls : ['./nav-vertical-subheader.component.scss']
})
export class FuseNavVerticalSubheaderComponent implements OnInit
{
@HostBinding('class') classes = 'nav-subheader';
@Input() item: any;
constructor()
{
}
ngOnInit()
{
}
}

View File

@@ -47,7 +47,7 @@
</md-input-container>
<md-divider></md-divider>
<md-nav-list *ngIf="!searching" style="max-height: 312px; overflow: auto" perfect-scrollbar>
<md-nav-list *ngIf="!searching" style="max-height: 312px; overflow: auto" fusePerfectScrollbar>
<md-list-item *ngFor="let shortcutItem of shortcutItems"
(click)="toggleShortcut($event, shortcutItem)">
@@ -68,7 +68,7 @@
</md-list-item>
</md-nav-list>
<md-nav-list *ngIf="searching" style="max-height: 312px; overflow: auto" perfect-scrollbar>
<md-nav-list *ngIf="searching" style="max-height: 312px; overflow: auto" fusePerfectScrollbar>
<md-list-item *ngFor="let navigationItem of filteredNavigationItems"
(click)="toggleShortcut($event, navigationItem)">
<div class="w-100-p" fxLayout="row" fxLayoutAlign="start center">

View File

@@ -4,103 +4,95 @@
<div class="theme-options-panel-overlay" #overlay [fxHide]="barClosed" [@fadeInOut]="!barClosed"></div>
<div #panel class="theme-options-panel md-white-bg mat-elevation-z8 p-16">
<div #panel class="theme-options-panel md-white-bg mat-elevation-z8">
<button md-icon-button class="close-button" (click)="closeBar()">
<md-icon>close</md-icon>
</button>
<md-list>
<h3 md-subheader>Navigation:</h3>
<md-list-item>
<md-radio-group [(ngModel)]="fuseSettings.layout.navigation" (ngModelChange)="onSettingsChange()">
<md-radio-button class="mr-8" value="top">Top</md-radio-button>
<md-radio-button class="mr-8" value="left">Left</md-radio-button>
<md-radio-button class="mr-8" value="right">Right</md-radio-button>
<md-radio-button class="mr-8" value="none">None</md-radio-button>
</md-radio-group>
</md-list-item>
<div class="theme-options-panel-inner" fxLayout="column" fxLayoutAlign="start start">
<h3 md-subheader>Toolbar:</h3>
<md-list-item>
<md-radio-group [(ngModel)]="fuseSettings.layout.toolbar" (ngModelChange)="onSettingsChange()">
<md-radio-button class="mr-8" value="below">Below</md-radio-button>
<md-radio-button class="mr-8" value="above">Above</md-radio-button>
<md-radio-button class="mr-8" value="none">None</md-radio-button>
</md-radio-group>
</md-list-item>
<h3>Navigation:</h3>
<md-radio-group [(ngModel)]="fuseSettings.layout.navigation" (ngModelChange)="onSettingsChange()"
fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign="start start" fxLayoutWrap>
<md-radio-button class="mr-8 mb-8" value="top">Top</md-radio-button>
<md-radio-button class="mr-8 mb-8" value="left">Left</md-radio-button>
<md-radio-button class="mr-8 mb-8" value="right">Right</md-radio-button>
<md-radio-button class="mr-8 mb-8" value="none">None</md-radio-button>
</md-radio-group>
<h3 md-subheader>Footer:</h3>
<md-list-item>
<md-radio-group [(ngModel)]="fuseSettings.layout.footer" (ngModelChange)="onSettingsChange()">
<md-radio-button class="mr-8" value="below">Below</md-radio-button>
<md-radio-button class="mr-8" value="above">Above</md-radio-button>
<md-radio-button class="mr-8" value="none">None</md-radio-button>
</md-radio-group>
</md-list-item>
<h3 class="mt-24">Toolbar:</h3>
<md-radio-group [(ngModel)]="fuseSettings.layout.toolbar" (ngModelChange)="onSettingsChange()"
fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign="start start" fxLayoutWrap>
<md-radio-button class="mr-8 mb-8" value="below">Below</md-radio-button>
<md-radio-button class="mr-8 mb-8" value="above">Above</md-radio-button>
<md-radio-button class="mr-8 mb-8" value="none">None</md-radio-button>
</md-radio-group>
<h3 md-subheader>Layout Mode:</h3>
<md-list-item>
<md-radio-group [(ngModel)]="fuseSettings.layout.mode" (ngModelChange)="onSettingsChange()">
<md-radio-button class="mr-8" value="boxed">Boxed</md-radio-button>
<md-radio-button class="mr-8" value="fullwidth">Fullwidth</md-radio-button>
</md-radio-group>
</md-list-item>
<h3 class="mt-24">Footer:</h3>
<md-radio-group [(ngModel)]="fuseSettings.layout.footer" (ngModelChange)="onSettingsChange()"
fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign="start start" fxLayoutWrap>
<md-radio-button class="mr-8 mb-8" value="below">Below</md-radio-button>
<md-radio-button class="mr-8 mb-8" value="above">Above</md-radio-button>
<md-radio-button class="mr-8 mb-8" value="none">None</md-radio-button>
</md-radio-group>
<h3 class="mt-24">Layout Mode:</h3>
<md-radio-group [(ngModel)]="fuseSettings.layout.mode" (ngModelChange)="onSettingsChange()"
fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign="start start" fxLayoutWrap>
<md-radio-button class="mr-8 mb-8" value="boxed">Boxed</md-radio-button>
<md-radio-button class="mr-8 mb-8" value="fullwidth">Fullwidth</md-radio-button>
</md-radio-group>
<md-divider></md-divider>
<h3 md-subheader>Colors:</h3>
<h3>Colors:</h3>
<div class="colors">
<md-list-item class="mb-8">
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center">
<h4>Toolbar Color</h4>
<fuse-material-color-picker [(selectedClass)]="fuseSettings.colorClasses.toolbar" (onValueChange)="onSettingsChange()"></fuse-material-color-picker>
<h4 class="mr-8">Toolbar Color</h4>
<fuse-material-color-picker [(selectedClass)]="fuseSettings.colorClasses.toolbar"
(onValueChange)="onSettingsChange()"></fuse-material-color-picker>
</div>
</md-list-item>
<md-list-item class="mb-8">
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center">
<h4>Navigation Bar Color</h4>
<fuse-material-color-picker [(selectedClass)]="fuseSettings.colorClasses.navbar" (onValueChange)="onSettingsChange()"></fuse-material-color-picker>
<h4 class="mr-8">Navigation Bar Color</h4>
<fuse-material-color-picker [(selectedClass)]="fuseSettings.colorClasses.navbar"
(onValueChange)="onSettingsChange()"></fuse-material-color-picker>
</div>
</md-list-item>
<md-list-item class="mb-8">
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center">
<h4>Footer Color</h4>
<fuse-material-color-picker [(selectedClass)]="fuseSettings.colorClasses.footer" (onValueChange)="onSettingsChange()"></fuse-material-color-picker>
<h4 class="mr-8">Footer Color</h4>
<fuse-material-color-picker [(selectedClass)]="fuseSettings.colorClasses.footer"
(onValueChange)="onSettingsChange()"></fuse-material-color-picker>
</div>
</md-list-item>
</div>
<md-divider></md-divider>
<h3 md-subheader>Animation:</h3>
<h3>Router Animation:</h3>
<md-select class="p-0" [(ngModel)]="fuseSettings.routerAnimation">
<md-option value="none">
None
</md-option>
<md-option value="slideUp">
Slide up
</md-option>
<md-option value="slideDown">
Slide down
</md-option>
<md-option value="slideRight">
Slide right
</md-option>
<md-option value="slideLeft">
Slide left
</md-option>
<md-option value="fadeIn">
Fade in
</md-option>
</md-select>
<md-list-item>
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center">
<h4>Router Animation</h4>
<md-select class="p-0" [(ngModel)]="fuseSettings.routerAnimation">
<md-option value="none">
None
</md-option>
<md-option value="slideUp">
Slide up
</md-option>
<md-option value="slideDown">
Slide down
</md-option>
<md-option value="slideRight">
Slide right
</md-option>
<md-option value="slideLeft">
Slide left
</md-option>
<md-option value="fadeIn">
Fade in
</md-option>
</md-select>
</div>
</md-list-item>
</div>
</md-list>
</div>

View File

@@ -15,6 +15,10 @@
right: 0;
top: 160px;
&.bar-closed .theme-options-panel {
display: none;
}
.theme-options-panel {
position: absolute;
right: 0;
@@ -22,12 +26,38 @@
width: 360px;
transform: translate3d(100%, 0, 0);
z-index: 999;
max-height: calc(100vh - 200px);
padding: 24px;
overflow: auto;
@include media-breakpoint-down('xs') {
top: -120px;
max-height: calc(100vh - 100px);
width: 90vw;
}
.close-button {
position: absolute;
top: 8px;
right: 8px;
}
h3 {
font-size: 14px;
font-weight: 500;
color: rgba(0, 0, 0, 0.54);
}
.mat-divider{
display: block !important;
width: 100%;
margin: 24px 0 16px 0;
}
.colors {
display: block !important;
width: 100%;
}
}
.theme-options-panel-overlay {
@@ -40,6 +70,10 @@
bottom: 0;
z-index: 998;
@include media-breakpoint-down('sm') {
background: rgba(0, 0, 0, 0.37);
}
&.hidden {
display: none;
}

View File

@@ -1,14 +1,14 @@
import { Component, ElementRef, OnDestroy, OnInit, Renderer2, ViewChild } from '@angular/core';
import { Component, ElementRef, HostBinding, OnDestroy, OnInit, Renderer2, ViewChild } from '@angular/core';
import { style, animate, AnimationBuilder, AnimationPlayer } from '@angular/animations';
import { Subscription } from 'rxjs/Subscription';
import { FuseConfigService } from '../../services/config.service';
import { Animations } from '../../animations';
import { fuseAnimations } from '../../animations';
@Component({
selector : 'fuse-theme-options',
templateUrl: './theme-options.component.html',
styleUrls : ['./theme-options.component.scss'],
animations : [Animations.fadeInOut]
animations : fuseAnimations
})
export class FuseThemeOptionsComponent implements OnInit, OnDestroy
{
@@ -18,10 +18,11 @@ export class FuseThemeOptionsComponent implements OnInit, OnDestroy
public player: AnimationPlayer;
fuseSettings: any;
barClosed: boolean;
onSettingsChanged: Subscription;
@HostBinding('class.bar-closed') barClosed: boolean;
constructor(
private animationBuilder: AnimationBuilder,
private fuseConfig: FuseConfigService,
@@ -53,8 +54,6 @@ export class FuseThemeOptionsComponent implements OnInit, OnDestroy
closeBar()
{
this.barClosed = true;
this.player =
this.animationBuilder
.build([
@@ -63,6 +62,10 @@ export class FuseThemeOptionsComponent implements OnInit, OnDestroy
]).create(this.panel.nativeElement);
this.player.play();
this.player.onDone(() => {
this.barClosed = true;
});
}
openBar()

View File

@@ -21,7 +21,7 @@ export class FuseIfOnDomDirective implements AfterContentChecked
{
setTimeout(() => {
this.viewContainer.createEmbeddedView(this.templateRef);
}, 0);
}, 350);
this.isCreated = true;
}
else if ( this.isCreated && !document.body.contains(this.element.nativeElement) )

View File

@@ -0,0 +1,173 @@
import { AfterViewInit, Directive, ElementRef, NgZone, OnDestroy, OnInit } from '@angular/core';
import * as Ps from 'perfect-scrollbar';
import { FuseConfigService } from '../../services/config.service';
import { Subscription } from 'rxjs/Subscription';
import { Platform } from '@angular/cdk/platform';
@Directive({
selector: '[fusePerfectScrollbar]'
})
export class FusePerfectScrollbarDirective implements OnInit, AfterViewInit, OnDestroy
{
onSettingsChanged: Subscription;
isDisableCustomScrollbars = false;
isMobile = false;
isInitialized = true;
constructor(
private element: ElementRef,
private zone: NgZone,
private fuseConfig: FuseConfigService,
private platform: Platform
)
{
this.onSettingsChanged =
this.fuseConfig.onSettingsChanged
.subscribe(
(settings) => {
this.isDisableCustomScrollbars = !settings.customScrollbars;
}
);
if ( this.platform.ANDROID || this.platform.IOS )
{
this.isMobile = true;
}
}
ngOnInit()
{
}
ngAfterViewInit()
{
if ( this.isMobile || this.isDisableCustomScrollbars )
{
this.isInitialized = false;
return;
}
this.zone.runOutsideAngular(() => {
// Initialize the perfect-scrollbar
Ps.initialize(this.element.nativeElement);
});
}
ngOnDestroy()
{
if ( !this.isInitialized )
{
return;
}
this.onSettingsChanged.unsubscribe();
// Destroy the perfect-scrollbar
Ps.destroy(this.element.nativeElement);
}
update()
{
if ( !this.isInitialized )
{
return;
}
// Update the perfect-scrollbar
Ps.update(this.element.nativeElement);
}
destroy()
{
this.ngOnDestroy();
}
scrollToX(x: number, speed?: number)
{
this.animateScrolling('scrollLeft', x, speed);
}
scrollToY(y: number, speed?: number)
{
this.animateScrolling('scrollTop', y, speed);
}
scrollToTop(offset?: number, speed?: number)
{
this.animateScrolling('scrollTop', (offset || 0), speed);
}
scrollToLeft(offset?: number, speed?: number)
{
this.animateScrolling('scrollLeft', (offset || 0), speed);
}
scrollToRight(offset?: number, speed?: number)
{
const width = this.element.nativeElement.scrollWidth;
this.animateScrolling('scrollLeft', width - (offset || 0), speed);
}
scrollToBottom(offset?: number, speed?: number)
{
const height = this.element.nativeElement.scrollHeight;
this.animateScrolling('scrollTop', height - (offset || 0), speed);
}
animateScrolling(target: string, value: number, speed?: number)
{
if ( !speed )
{
this.element.nativeElement[target] = value;
// PS has weird event sending order, this is a workaround for that
this.update();
this.update();
}
else if ( value !== this.element.nativeElement[target] )
{
let newValue = 0;
let scrollCount = 0;
let oldTimestamp = performance.now();
let oldValue = this.element.nativeElement[target];
const cosParameter = (oldValue - value) / 2;
const step = (newTimestamp) => {
scrollCount += Math.PI / (speed / (newTimestamp - oldTimestamp));
newValue = Math.round(value + cosParameter + cosParameter * Math.cos(scrollCount));
// Only continue animation if scroll position has not changed
if ( this.element.nativeElement[target] === oldValue )
{
if ( scrollCount >= Math.PI )
{
this.element.nativeElement[target] = value;
// PS has weird event sending order, this is a workaround for that
this.update();
this.update();
}
else
{
this.element.nativeElement[target] = oldValue = newValue;
oldTimestamp = newTimestamp;
window.requestAnimationFrame(step);
}
}
};
window.requestAnimationFrame(step);
}
}
}

View File

@@ -1,4 +1,4 @@
import { Directive, Input, OnInit, HostListener, OnDestroy, HostBinding, AfterViewInit } from '@angular/core';
import { Directive, Input, OnInit, HostListener, OnDestroy, HostBinding } from '@angular/core';
import { MdSidenav } from '@angular/material';
import { FuseMdSidenavHelperService } from 'app/core/directives/md-sidenav-helper/md-sidenav-helper.service';
import { FuseMatchMedia } from '../../services/match-media.service';
@@ -8,7 +8,7 @@ import { Subscription } from 'rxjs/Subscription';
@Directive({
selector: '[fuseMdSidenavHelper]'
})
export class FuseMdSidenavHelperDirective implements OnInit, AfterViewInit, OnDestroy
export class FuseMdSidenavHelperDirective implements OnInit, OnDestroy
{
matchMediaSubscription: Subscription;
@@ -38,6 +38,7 @@ export class FuseMdSidenavHelperDirective implements OnInit, AfterViewInit, OnDe
this.mdSidenav.mode = 'side';
this.mdSidenav.open();
});
this.stopTransition = false;
}
else
{
@@ -46,6 +47,10 @@ export class FuseMdSidenavHelperDirective implements OnInit, AfterViewInit, OnDe
this.mdSidenav.mode = 'over';
this.mdSidenav.close();
});
setTimeout(() => {
this.stopTransition = false;
}, 3000);
}
this.matchMediaSubscription = this.fuseMatchMedia.onMediaChange.subscribe(() => {
@@ -69,13 +74,6 @@ export class FuseMdSidenavHelperDirective implements OnInit, AfterViewInit, OnDe
}
ngAfterViewInit()
{
setTimeout(() => {
this.stopTransition = false;
}, 0);
}
ngOnDestroy()
{
this.matchMediaSubscription.unsubscribe();

View File

@@ -1,6 +1,5 @@
export class FuseUtils
{
public static filterArrayByString(mainArr, searchText)
{
if ( searchText === '' )
@@ -17,7 +16,6 @@ export class FuseUtils
public static searchInObj(itemObj, searchText)
{
for ( const prop in itemObj )
{
if ( !itemObj.hasOwnProperty(prop) )
@@ -29,7 +27,7 @@ export class FuseUtils
if ( typeof value === 'string' )
{
if ( this.searchInSting(value, searchText) )
if ( this.searchInString(value, searchText) )
{
return true;
}
@@ -41,7 +39,6 @@ export class FuseUtils
{
return true;
}
}
if ( typeof value === 'object' )
@@ -60,7 +57,7 @@ export class FuseUtils
{
if ( typeof value === 'string' )
{
if ( this.searchInSting(value, searchText) )
if ( this.searchInString(value, searchText) )
{
return true;
}
@@ -76,7 +73,7 @@ export class FuseUtils
}
}
public static searchInSting(value, searchText)
public static searchInString(value, searchText)
{
return value.toLowerCase().includes(searchText);
}

View File

@@ -4,7 +4,6 @@ import { CommonModule } from '@angular/common';
import { MaterialModule } from './material.module';
import { FlexLayoutModule } from '@angular/flex-layout';
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
import { ColorPickerModule } from 'ngx-color-picker';
import { NgxDnDModule } from '@swimlane/ngx-dnd';
import { NgxDatatableModule } from '@swimlane/ngx-datatable';
@@ -13,11 +12,11 @@ import { FuseMdSidenavHelperDirective, FuseMdSidenavTogglerDirective } from '../
import { FusePipesModule } from '../pipes/pipes.module';
import { FuseConfirmDialogComponent } from '../components/confirm-dialog/confirm-dialog.component';
import { FuseCountdownComponent } from '../components/countdown/countdown.component';
import { FuseNavigationService } from '../components/navigation/navigation.service';
import { FuseMatchMedia } from '../services/match-media.service';
import { FuseNavbarVerticalService } from '../../main/navbar/vertical/navbar-vertical.service';
import { FuseMdSidenavHelperService } from '../directives/md-sidenav-helper/md-sidenav-helper.service';
import { FuseHljsComponent } from '../components/hljs/hljs.component';
import { FusePerfectScrollbarDirective } from '../directives/fuse-perfect-scrollbar/fuse-perfect-scrollbar.directive';
import { FuseIfOnDomDirective } from '../directives/fuse-if-on-dom/fuse-if-on-dom.directive';
import { FuseMaterialColorPickerComponent } from '../components/material-color-picker/material-color-picker.component';
import { Md2Module } from 'md2';
@@ -31,6 +30,7 @@ import { CookieService } from 'ngx-cookie-service';
FuseCountdownComponent,
FuseHljsComponent,
FuseIfOnDomDirective,
FusePerfectScrollbarDirective,
FuseMaterialColorPickerComponent
],
imports : [
@@ -39,7 +39,6 @@ import { CookieService } from 'ngx-cookie-service';
CommonModule,
FormsModule,
FusePipesModule,
PerfectScrollbarModule,
ReactiveFormsModule,
ColorPickerModule,
NgxDnDModule,
@@ -56,7 +55,7 @@ import { CookieService } from 'ngx-cookie-service';
FusePipesModule,
FuseCountdownComponent,
FuseHljsComponent,
PerfectScrollbarModule,
FusePerfectScrollbarDirective,
ReactiveFormsModule,
ColorPickerModule,
NgxDnDModule,
@@ -70,7 +69,6 @@ import { CookieService } from 'ngx-cookie-service';
],
providers : [
CookieService,
FuseNavigationService,
FuseMatchMedia,
FuseNavbarVerticalService,
FuseMdSidenavHelperService

View File

@@ -2,8 +2,8 @@
@import '~@swimlane/ngx-datatable/release/index.css';
@import '~@swimlane/ngx-datatable/release/themes/material.css';
@import '~@swimlane/ngx-datatable/release/assets/icons.css';
// Perfect Scrollbar
@import "~perfect-scrollbar/src/css/main";
// Perfect scrollbar
@import '~perfect-scrollbar/dist/css/perfect-scrollbar.min.css';
// Fuse
@import "fuse";

View File

@@ -4,3 +4,38 @@
border-radius: 50%;
}
}
md-sidenav-container {
md-sidenav {
&[md-is-locked-open].md-stop-transition {
transition: none !important;
transform: translate3d(0, 0, 0) !important;
opacity: 0;
~ .mat-sidenav-content,
~ .mat-drawer-content {
transition: none !important;
}
}
&.mat-sidenav-opened {
&.mat-drawer-side {
~ .mat-sidenav-content,
~ .mat-drawer-content {
transition: none !important;
transform: translate3d(0, 0, 0) !important;
}
}
}
&.mat-drawer-end {
}
}
.mat-drawer-content {
}
}

View File

@@ -11,6 +11,21 @@
white-space: nowrap;
}
.nav-group {
> .group-title {
position: relative;
display: flex;
align-items: center;
height: 48px;
font-weight: 500;
padding-left: 24px;
margin-top: 8px;
font-size: 12px;
white-space: nowrap;
}
}
.nav-item {
.nav-link {
@@ -119,6 +134,31 @@
}
}
> .nav-group {
> .group-items {
> .nav-collapse {
background: transparent;
transition: background 200ms ease-in-out;
&.open {
background: rgba(0, 0, 0, 0.12);
}
}
}
}
&.vertical {
.nav-group {
.group-title {
text-transform: uppercase;
}
}
}
&.horizontal {
display: flex;
flex-direction: row;

View File

@@ -137,19 +137,10 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
@include mat-elevation(7);
&.md-is-locked-open {
position: relative;
background: none;
box-shadow: none;
}
&.md-stop-transition {
~ .mat-sidenav-content,
~ .mat-drawer-content {
transition: none;
}
}
.header {
height: $carded-header-height;
min-height: $carded-header-height;
@@ -233,7 +224,6 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
~ .mat-sidenav-content,
~ .mat-drawer-content {
margin-left: 0 !important;
.center {
margin-left: 0;
@@ -257,7 +247,6 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
~ .mat-sidenav-content,
~ .mat-drawer-content {
margin-right: 0 !important;
.center {
margin-right: 0;
@@ -284,6 +273,10 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
}
// Fullwidth
&.fullwidth {
overflow: auto;
}
&.fullwidth,
&.inner-sidenav {
min-height: 100%;
@@ -309,10 +302,6 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
> .mat-drawer-content {
flex: 1 0 auto;
max-height: none;
> .center {
overflow: hidden;
}
}
}
}
@@ -352,6 +341,7 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
> md-sidenav-container {
display: flex;
flex-direction: column;
//flex-direction: row;
flex: 1;
background: none;
z-index: 2;
@@ -372,14 +362,6 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
background: transparent;
}
&.md-stop-transition {
~ .mat-sidenav-content,
~ .mat-drawer-content {
transition: none;
}
}
.sidenav-content {
height: 100%;
}
@@ -467,7 +449,6 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
&.simple {
&.fullwidth {
overflow: visible;
> .content {
flex: 1 0 auto;
@@ -483,10 +464,6 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
> .mat-sidenav-content,
> .mat-drawer-content {
flex: 1 0 auto;
> .center {
overflow: hidden;
}
}
}
}

View File

@@ -1,20 +1,23 @@
::-webkit-scrollbar {
width: 12px;
height: 12px;
background-color: rgba(0, 0, 0, 0);
}
body:not(.is-mobile) {
::-webkit-scrollbar:hover {
background-color: rgba(0, 0, 0, 0.12);
}
::-webkit-scrollbar {
width: 12px;
height: 12px;
background-color: rgba(0, 0, 0, 0);
}
::-webkit-scrollbar-thumb {
border: 2px solid transparent;
box-shadow: inset 0 0 0 24px rgba(0, 0, 0, 0.37);
border-radius: 24px;
}
::-webkit-scrollbar:hover {
background-color: rgba(0, 0, 0, 0.12);
}
::-webkit-scrollbar-thumb:active {
box-shadow: inset 0 0 0 24px rgba(0, 0, 0, 0.54);
border-radius: 24px;
::-webkit-scrollbar-thumb {
border: 2px solid transparent;
box-shadow: inset 0 0 0 24px rgba(0, 0, 0, 0.37);
border-radius: 24px;
}
::-webkit-scrollbar-thumb:active {
box-shadow: inset 0 0 0 24px rgba(0, 0, 0, 0.54);
border-radius: 24px;
}
}

View File

@@ -1,4 +1,5 @@
.ps {
position: relative;
> .ps__scrollbar-y-rail {
z-index: 99999;

View File

@@ -30,7 +30,7 @@ export class FuseConfigService
colorClasses : {
toolbar: 'md-white-500-bg',
navbar : 'md-fuse-dark-500-bg',
footer : 'md-fuse-dark-800-bg'
footer : 'md-fuse-dark-700-bg'
},
customScrollbars: true,
routerAnimation : 'fadeIn'

View File

@@ -0,0 +1,97 @@
import {
startOfDay,
endOfDay,
subDays,
addDays,
endOfMonth,
isSameDay,
isSameMonth,
addHours
} from 'date-fns';
export class CalendarFakeDb
{
public static data = [
{
id : 'events',
data: [
{
start : subDays(startOfDay(new Date()), 1),
end : addDays(new Date(), 1),
title : 'A 3 day event',
allDay : false,
color : {
primary : '#ad2121',
secondary: '#FAE3E3'
},
resizable: {
beforeStart: true,
afterEnd : true
},
draggable: true,
meta : {
location: 'Los Angeles',
notes : 'Eos eu verear adipiscing, ex ornatus denique iracundia sed, quodsi oportere appellantur an pri.'
}
},
{
start : startOfDay(new Date()),
title : 'An event with no end date',
allDay : false,
color : {
primary : '#e3bc08',
secondary: '#FDF1BA'
},
resizable: {
beforeStart: true,
afterEnd : true
},
draggable: true,
meta : {
location: 'Los Angeles',
notes : 'Eos eu verear adipiscing, ex ornatus denique iracundia sed, quodsi oportere appellantur an pri.'
}
},
{
start : subDays(endOfMonth(new Date()), 3),
end : addDays(endOfMonth(new Date()), 3),
title : 'A long event that spans 2 months',
allDay : false,
color : {
primary : '#1e90ff',
secondary: '#D1E8FF'
},
resizable: {
beforeStart: true,
afterEnd : true
},
draggable: true,
meta : {
location: 'Los Angeles',
notes : 'Eos eu verear adipiscing, ex ornatus denique iracundia sed, quodsi oportere appellantur an pri.'
}
},
{
start : addHours(startOfDay(new Date()), 2),
end : new Date(),
title : 'A draggable and resizable event',
allDay : false,
color : {
primary : '#e3bc08',
secondary: '#FDF1BA'
},
resizable: {
beforeStart: true,
afterEnd : true
},
draggable: true,
meta : {
location: 'Los Angeles',
notes : 'Eos eu verear adipiscing, ex ornatus denique iracundia sed, quodsi oportere appellantur an pri.'
}
}
]
}
];
}

View 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 doesnt 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': 'Im having breakfast right now, cant 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': 'Its 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': 'Its 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': 'Its 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': 'Its 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': 'Im having breakfast right now, cant 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'
}
]
}
];
}

View File

@@ -0,0 +1,411 @@
export class ContactsFakeDb
{
public static contacts = [
{
'id' : '5725a680b3249760ea21de52',
'name' : 'Abbott',
'lastName': 'Keitch',
'avatar' : 'assets/images/avatars/Abbott.jpg',
'nickname': 'Royalguard',
'company' : 'Saois',
'jobTitle': 'Digital Archivist',
'email' : 'abbott@withinpixels.com',
'phone' : '+1-202-555-0175',
'address' : '933 8th Street Stamford, CT 06902',
'birthday': null,
'notes' : ''
},
{
'id' : '5725a680606588342058356d',
'name' : 'Arnold',
'lastName': 'Matlock',
'avatar' : 'assets/images/avatars/Arnold.jpg',
'nickname': 'Wanderer',
'company' : 'Laotcone',
'jobTitle': 'Graphic Artist',
'email' : 'arnold@withinpixels.com',
'phone' : '+1-202-555-0141',
'address' : '906 Valley Road Michigan City, IN 46360',
'birthday': null,
'notes' : ''
},
{
'id' : '5725a68009e20d0a9e9acf2a',
'name' : 'Barrera',
'lastName': 'Bradbury',
'avatar' : 'assets/images/avatars/Barrera.jpg',
'nickname': 'Jackal',
'company' : 'Unizim',
'jobTitle': 'Graphic Designer',
'email' : 'barrera@withinpixels.com',
'phone' : '+1-202-555-0196',
'address' : '183 River Street Passaic, NJ 07055',
'birthday': null,
'notes' : ''
},
{
'id' : '5725a6809fdd915739187ed5',
'name' : 'Blair',
'lastName': 'Strangeway',
'avatar' : 'assets/images/avatars/Blair.jpg',
'nickname': 'Knight',
'company' : 'Conedubdax',
'jobTitle': 'Visual Designer',
'email' : 'blair@withinpixels.com',
'phone' : '+1-202-555-0118',
'address' : '143 Jones Street Eau Claire, WI 54701',
'birthday': null,
'notes' : ''
},
{
'id' : '5725a68007920cf75051da64',
'name' : 'Boyle',
'lastName': 'Winters',
'avatar' : 'assets/images/avatars/Boyle.jpg',
'nickname': 'Jester',
'company' : 'Newo',
'jobTitle': 'Catalogue Illustrator',
'email' : 'boyle@withinpixels.com',
'phone' : '+1-202-555-0177',
'address' : '218 Pearl Street Brandon, FL 33510',
'birthday': null,
'notes' : ''
},
{
'id' : '5725a68031fdbb1db2c1af47',
'name' : 'Christy',
'lastName': 'Camacho',
'avatar' : 'assets/images/avatars/Christy.jpg',
'nickname': 'Mist',
'company' : 'uniway',
'jobTitle': '3D Animator',
'email' : 'christy@withinpixels.com',
'phone' : '+1-202-555-0136',
'address' : '329 Bridge Street Desoto, TX 75115',
'birthday': null,
'notes' : ''
},
{
'id' : '5725a680bc670af746c435e2',
'name' : 'Copeland',
'lastName': 'Redcliff',
'avatar' : 'assets/images/avatars/Copeland.jpg',
'nickname': 'Cloudlaw',
'company' : 'Tempron',
'jobTitle': 'Multimedia Artist',
'email' : 'copeland@withinpixels.com',
'phone' : '+1-202-555-0107',
'address' : '956 6th Avenue North Bergen, NJ 0704',
'birthday': null,
'notes' : ''
},
{
'id' : '5725a680e7eb988a58ddf303',
'name' : 'Estes',
'lastName': 'Stevens',
'avatar' : 'assets/images/avatars/Estes.jpg',
'nickname': 'Roamer',
'company' : 'nam-dex',
'jobTitle': 'Special Effects Artist',
'email' : 'estes@withinpixels.com',
'phone' : '+1-202-555-0113',
'address' : '664 York Street Cambridge, MA 02138',
'birthday': null,
'notes' : ''
},
{
'id' : '5725a680dcb077889f758961',
'name' : 'Harper',
'lastName': 'MacGuffin',
'avatar' : 'assets/images/avatars/Harper.jpg',
'nickname': 'Tempest',
'company' : 'runcane',
'jobTitle': 'Application Developer',
'email' : 'harper@withinpixels.com',
'phone' : '+1-202-555-0173',
'address' : '738 Route 11 Cornelius, NC 28031',
'birthday': null,
'notes' : ''
},
{
'id' : '5725a6806acf030f9341e925',
'name' : 'Helen',
'lastName': 'Sheridan',
'avatar' : 'assets/images/avatars/Helen.jpg',
'nickname': 'Magicbattler',
'company' : 'Subhow',
'jobTitle': 'Content Developer',
'email' : 'helen@withinpixels.com',
'phone' : '+1-202-555-0163',
'address' : '194 Washington Avenue Saint Petersburg, FL 33702',
'birthday': null,
'notes' : ''
},
{
'id' : '5725a680ae1ae9a3c960d487',
'name' : 'Henderson',
'lastName': 'Cambias',
'avatar' : 'assets/images/avatars/Henderson.jpg',
'nickname': 'Blizzard',
'company' : 'Howcom',
'jobTitle': 'Web Designer',
'email' : 'henderson@withinpixels.com',
'phone' : '+1-202-555-0151',
'address' : '686 Roosevelt Avenue Oviedo, FL 32765',
'birthday': null,
'notes' : ''
},
{
'id' : '5725a680b8d240c011dd224b',
'name' : 'Josefina',
'lastName': 'Lakefield',
'avatar' : 'assets/images/avatars/Josefina.jpg',
'nickname': 'Violet',
'company' : 'Gecko',
'jobTitle': 'Web Developer',
'email' : 'josefina@withinpixels.com',
'phone' : '+1-202-555-0160',
'address' : '202 Hartford Road Lynchburg, VA 24502',
'birthday': null,
'notes' : ''
},
{
'id' : '5725a68034cb3968e1f79eac',
'name' : 'Katina',
'lastName': 'Bletchley',
'avatar' : 'assets/images/avatars/Katina.jpg',
'nickname': 'Rose',
'company' : 'Lexicom',
'jobTitle': 'Software Designer',
'email' : 'katina@withinpixels.com',
'phone' : '+1-202-555-0186',
'address' : '219 Woodland Road Valrico, FL 33594',
'birthday': null,
'notes' : ''
},
{
'id' : '5725a6801146cce777df2a08',
'name' : 'Lily',
'lastName': 'Peasegood',
'avatar' : 'assets/images/avatars/Lily.jpg',
'nickname': 'Star',
'company' : 'zooflex',
'jobTitle': 'Software Specialist',
'email' : 'lily@withinpixels.com',
'phone' : '+1-202-555-0115',
'address' : '305 Willow Drive Superior, WI 54880',
'birthday': null,
'notes' : ''
},
{
'id' : '5725a6808a178bfd034d6ecf',
'name' : 'Mai',
'lastName': 'Nox',
'avatar' : 'assets/images/avatars/Mai.jpg',
'nickname': 'Violetmage',
'company' : 'quadzone',
'jobTitle': 'Software Engineer',
'email' : 'mai@withinpixels.com',
'phone' : '+1-202-555-0199',
'address' : '148 Heather Lane Mcminnville, TN 37110',
'birthday': null,
'notes' : ''
},
{
'id' : '5725a680653c265f5c79b5a9',
'name' : 'Nancy',
'lastName': 'Jaggers',
'avatar' : 'assets/images/avatars/Nancy.jpg',
'nickname': 'Silverwarden',
'company' : 'Opetamnix',
'jobTitle': 'Software Architect',
'email' : 'nancy@withinpixels.com',
'phone' : '+1-202-555-0120',
'address' : '345 Laurel Lane Union City, NJ 07087',
'birthday': null,
'notes' : ''
},
{
'id' : '5725a680bbcec3cc32a8488a',
'name' : 'Nora',
'lastName': 'Franklin',
'avatar' : 'assets/images/avatars/Nora.jpg',
'nickname': 'Katanachanter',
'company' : 'Saoway',
'jobTitle': 'Database Coordinator',
'email' : 'nora@withinpixels.com',
'phone' : '+1-202-555-0172',
'address' : '572 Rose Street Summerfield, FL 34491',
'birthday': null,
'notes' : ''
},
{
'id' : '5725a6803d87f1b77e17b62b',
'name' : 'Odessa',
'lastName': 'Goodman',
'avatar' : 'assets/images/avatars/Odessa.jpg',
'nickname': 'Rose',
'company' : 'transace',
'jobTitle': 'Database Administration Manager',
'email' : 'odessa@withinpixels.com',
'phone' : '+1-202-555-0190',
'address' : '527 Jefferson Court Conyers, GA 30012',
'birthday': null,
'notes' : ''
},
{
'id' : '5725a680e87cb319bd9bd673',
'name' : 'Reyna',
'lastName': 'Preece',
'avatar' : 'assets/images/avatars/Reyna.jpg',
'nickname': 'Holydawn',
'company' : 'Dingex',
'jobTitle': 'Data Processing Planner',
'email' : 'reyna@withinpixels.com',
'phone' : '+1-202-555-0116',
'address' : '297 Strawberry Lane Faribault, MN 55021',
'birthday': null,
'notes' : ''
},
{
'id' : '5725a6802d10e277a0f35775',
'name' : 'Shauna',
'lastName': 'Atherton',
'avatar' : 'assets/images/avatars/Shauna.jpg',
'nickname': 'Faunasoul',
'company' : 'Vivaflex',
'jobTitle': 'Art Director',
'email' : 'shauna@withinpixels.com',
'phone' : '+1-202-555-0159',
'address' : '928 Canterbury Court Pittsburgh, PA 15206',
'birthday': null,
'notes' : ''
},
{
'id' : '5725a680aef1e5cf26dd3d1f',
'name' : 'Shepard',
'lastName': 'Rosco',
'avatar' : 'assets/images/avatars/Shepard.jpg',
'nickname': 'Fireking',
'company' : 'Goldenla',
'jobTitle': 'Magazine Designer',
'email' : 'shepard@withinpixels.com',
'phone' : '+1-202-555-0173',
'address' : '904 Ridge Road Pickerington, OH 43147',
'birthday': null,
'notes' : ''
},
{
'id' : '5725a680cd7efa56a45aea5d',
'name' : 'Tillman',
'lastName': 'Lee',
'avatar' : 'assets/images/avatars/Tillman.jpg',
'nickname': 'Gust',
'company' : 'K-techno',
'jobTitle': 'News Photographer',
'email' : 'tillman@withinpixels.com',
'phone' : '+1-202-555-0183',
'address' : '447 Charles Street Dorchester, MA 02125',
'birthday': null,
'notes' : ''
},
{
'id' : '5725a680fb65c91a82cb35e2',
'name' : 'Trevino',
'lastName': 'Bush',
'avatar' : 'assets/images/avatars/Trevino.jpg',
'nickname': 'Wolf',
'company' : 'Dalthex',
'jobTitle': 'Photojournalist',
'email' : 'trevino@withinpixels.com',
'phone' : '+1-202-555-0138',
'address' : '84 Valley View Road Norman, OK 73072',
'birthday': null,
'notes' : ''
},
{
'id' : '5725a68018c663044be49cbf',
'name' : 'Tyson',
'lastName': 'Marshall',
'avatar' : 'assets/images/avatars/Tyson.jpg',
'nickname': 'Honordread',
'company' : 'Geocon',
'jobTitle': 'Manuscript Editor',
'email' : 'tyson@withinpixels.com',
'phone' : '+1-202-555-0146',
'address' : '204 Clark Street Monsey, NY 10952',
'birthday': null,
'notes' : ''
},
{
'id' : '5725a6809413bf8a0a5272b1',
'name' : 'Velazquez',
'lastName': 'Smethley',
'avatar' : 'assets/images/avatars/Velazquez.jpg',
'nickname': 'Strifedream',
'company' : 'ranex',
'jobTitle': 'Publications Editor',
'email' : 'velezquez@withinpixels.com',
'phone' : '+1-202-555-0146',
'address' : '261 Cleveland Street Riverside, NJ 08075',
'birthday': null,
'notes' : ''
}
];
public static user = [
{
'id' : '5725a6802d10e277a0f35724',
'name' : 'John Doe',
'avatar' : 'assets/images/avatars/profile.jpg',
'starred' : [
'5725a680ae1ae9a3c960d487',
'5725a6801146cce777df2a08',
'5725a680bbcec3cc32a8488a',
'5725a680bc670af746c435e2',
'5725a68009e20d0a9e9acf2a'
],
'frequentContacts': [
'5725a6809fdd915739187ed5',
'5725a68031fdbb1db2c1af47',
'5725a680606588342058356d',
'5725a680e7eb988a58ddf303',
'5725a6806acf030f9341e925',
'5725a68034cb3968e1f79eac',
'5725a6801146cce777df2a08',
'5725a680653c265f5c79b5a9'
],
'groups' : [
{
'id' : '5725a6802d10e277a0f35739',
'name' : 'Friends',
'contactIds': [
'5725a680bbcec3cc32a8488a',
'5725a680e87cb319bd9bd673',
'5725a6802d10e277a0f35775'
]
},
{
'id' : '5725a6802d10e277a0f35749',
'name' : 'Clients',
'contactIds': [
'5725a680cd7efa56a45aea5d',
'5725a68018c663044be49cbf',
'5725a6809413bf8a0a5272b1',
'5725a6803d87f1b77e17b62b'
]
},
{
'id' : '5725a6802d10e277a0f35329',
'name' : 'Recent Workers',
'contactIds': [
'5725a680bbcec3cc32a8488a',
'5725a680653c265f5c79b5a9',
'5725a6808a178bfd034d6ecf',
'5725a6801146cce777df2a08'
]
}
]
}
];
}

View File

@@ -0,0 +1,146 @@
export class FileManagerFakeDb
{
public static files = [
{
'name' : 'Work Documents',
'type' : 'folder',
'owner' : 'me',
'size' : '',
'modified' : 'July 8, 2017',
'opened' : 'July 8, 2017',
'created' : 'July 8, 2017',
'extention': '',
'location' : 'My Files > Documents',
'offline' : true
},
{
'name' : 'Public Documents',
'type' : 'folder',
'owner' : 'public',
'size' : '',
'modified' : 'July 8, 2017',
'opened' : 'July 8, 2017',
'created' : 'July 8, 2017',
'extention': '',
'location' : 'My Files > Documents',
'offline' : true
},
{
'name' : 'Private Documents',
'type' : 'folder',
'owner' : 'me',
'size' : '',
'modified' : 'July 8, 2017',
'opened' : 'July 8, 2017',
'created' : 'July 8, 2017',
'extention': '',
'location' : 'My Files > Documents',
'offline' : true
},
{
'name' : 'Ongoing projects',
'type' : 'document',
'owner' : 'Emily Bennett',
'size' : '1.2 Mb',
'modified' : 'July 8, 2017',
'opened' : 'July 8, 2017',
'created' : 'July 8, 2017',
'extention': '',
'location' : 'My Files > Documents',
'offline' : true,
'preview' : 'assets/images/etc/sample-file-preview.jpg'
},
{
'name' : 'Shopping list',
'type' : 'document',
'owner' : 'Emily Bennett',
'size' : '980 Kb',
'modified' : 'July 8, 2017',
'opened' : 'July 8, 2017',
'created' : 'July 8, 2017',
'extention': '',
'location' : 'My Files > Documents',
'offline' : true,
'preview' : 'assets/images/etc/sample-file-preview.jpg'
},
{
'name' : 'Invoices',
'type' : 'spreadsheet',
'owner' : 'Emily Bennett',
'size' : '750 Kb',
'modified' : 'July 8, 2017',
'opened' : 'July 8, 2017',
'created' : 'July 8, 2017',
'extention': '',
'location' : 'My Files > Documents',
'offline' : true,
'preview' : 'assets/images/etc/sample-file-preview.jpg'
},
{
'name' : 'Crash logs',
'type' : 'document',
'owner' : 'Emily Bennett',
'size' : '980 Mb',
'modified' : 'July 8, 2017',
'opened' : 'July 8, 2017',
'created' : 'July 8, 2017',
'extention': '',
'location' : 'My Files > Documents',
'offline' : true,
'preview' : 'assets/images/etc/sample-file-preview.jpg'
},
{
'name' : 'System logs',
'type' : 'document',
'owner' : 'Emily Bennett',
'size' : '52 Kb',
'modified' : 'July 8, 2017',
'opened' : 'July 8, 2017',
'created' : 'July 8, 2017',
'extention': '',
'location' : 'My Files > Documents',
'offline' : true,
'preview' : 'assets/images/etc/sample-file-preview.jpg'
},
{
'name' : 'Prices',
'type' : 'spreadsheet',
'owner' : 'Emily Bennett',
'size' : '27 Mb',
'modified' : 'July 8, 2017',
'opened' : 'July 8, 2017',
'created' : 'July 8, 2017',
'extention': '',
'location' : 'My Files > Documents',
'offline' : true,
'preview' : 'assets/images/etc/sample-file-preview.jpg'
},
{
'name' : 'Anabelle Manual',
'type' : 'document',
'owner' : 'Emily Bennett',
'size' : '1.1 Kb',
'modified' : 'July 8, 2017',
'opened' : 'July 8, 2017',
'created' : 'July 8, 2017',
'extention': '',
'location' : 'My Files > Documents',
'offline' : true,
'preview' : 'assets/images/etc/sample-file-preview.jpg'
},
{
'name' : 'Steam summer sale budget',
'type' : 'spreadsheet',
'owner' : 'Emily Bennett',
'size' : '505 Kb',
'modified' : 'July 8, 2017',
'opened' : 'July 8, 2017',
'created' : 'July 8, 2017',
'extention': '',
'location' : 'My Files > Documents',
'offline' : true,
'preview' : 'assets/images/etc/sample-file-preview.jpg'
}
];
}

View File

@@ -0,0 +1,50 @@
import { InMemoryDbService } from 'angular-in-memory-web-api';
import { MailFakeDb } from './mail';
import { ChatFakeDb } from './chat';
import { CalendarFakeDb } from './calendar';
import { TodoFakeDb } from './todo';
import { ProfileFakeDb } from './profile';
import { ContactsFakeDb } from './contacts';
import { InvoiceFakeDb } from './invoice';
import { FileManagerFakeDb } from './file-manager';
import { SearchFakeDb } from './search';
import { QuickPanelFakeDb } from './quick-panel';
import { IconsFakeDb } from './icons';
import { ProjectsDashboardDb } from './projects-dashboard';
import { ScrumboardFakeDb } from './scrumboard';
export class FuseFakeDbService implements InMemoryDbService
{
createDb()
{
return {
'mail-mails' : MailFakeDb.mails,
'mail-folders' : MailFakeDb.folders,
'mail-filters' : MailFakeDb.filters,
'mail-labels' : MailFakeDb.labels,
'chat-contacts' : ChatFakeDb.contacts,
'chat-chats' : ChatFakeDb.chats,
'chat-user' : ChatFakeDb.user,
'calendar' : CalendarFakeDb.data,
'todo-todos' : TodoFakeDb.todos,
'todo-filters' : TodoFakeDb.filters,
'todo-tags' : TodoFakeDb.tags,
'profile-timeline' : ProfileFakeDb.timeline,
'profile-photos-videos' : ProfileFakeDb.photosVideos,
'profile-about' : ProfileFakeDb.about,
'contacts-contacts' : ContactsFakeDb.contacts,
'contacts-user' : ContactsFakeDb.user,
'invoice' : InvoiceFakeDb.invoice,
'file-manager' : FileManagerFakeDb.files,
'search-classic' : SearchFakeDb.classic,
'search-table' : SearchFakeDb.table,
'quick-panel-notes' : QuickPanelFakeDb.notes,
'quick-panel-events' : QuickPanelFakeDb.events,
'icons' : IconsFakeDb.icons,
'projects-dashboard-projects': ProjectsDashboardDb.projects,
'projects-dashboard-widgets' : ProjectsDashboardDb.widgets,
'scrumboard-boards' : ScrumboardFakeDb.boards
};
}
}

View File

@@ -0,0 +1,938 @@
export class IconsFakeDb
{
public static icons = [
'3d_rotation',
'ac_unit',
'access_alarm',
'access_alarms',
'access_time',
'accessibility',
'accessible',
'account_balance',
'account_balance_wallet',
'account_box',
'account_circle',
'adb',
'add',
'add_a_photo',
'add_alarm',
'add_alert',
'add_box',
'add_circle',
'add_circle_outline',
'add_location',
'add_shopping_cart',
'add_to_photos',
'add_to_queue',
'adjust',
'airline_seat_flat',
'airline_seat_flat_angled',
'airline_seat_individual_suite',
'airline_seat_legroom_extra',
'airline_seat_legroom_normal',
'airline_seat_legroom_reduced',
'airline_seat_recline_extra',
'airline_seat_recline_normal',
'airplanemode_active',
'airplanemode_inactive',
'airplay',
'airport_shuttle',
'alarm',
'alarm_add',
'alarm_off',
'alarm_on',
'album',
'all_inclusive',
'all_out',
'android',
'announcement',
'apps',
'archive',
'arrow_back',
'arrow_downward',
'arrow_drop_down',
'arrow_drop_down_circle',
'arrow_drop_up',
'arrow_forward',
'arrow_upward',
'art_track',
'aspect_ratio',
'assessment',
'assignment',
'assignment_ind',
'assignment_late',
'assignment_return',
'assignment_returned',
'assignment_turned_in',
'assistant',
'assistant_photo',
'attach_file',
'attach_money',
'attachment',
'audiotrack',
'autorenew',
'av_timer',
'backspace',
'backup',
'battery_alert',
'battery_charging_full',
'battery_full',
'battery_std',
'battery_unknown',
'beach_access',
'beenhere',
'block',
'bluetooth',
'bluetooth_audio',
'bluetooth_connected',
'bluetooth_disabled',
'bluetooth_searching',
'blur_circular',
'blur_linear',
'blur_off',
'blur_on',
'book',
'bookmark',
'bookmark_border',
'border_all',
'border_bottom',
'border_clear',
'border_color',
'border_horizontal',
'border_inner',
'border_left',
'border_outer',
'border_right',
'border_style',
'border_top',
'border_vertical',
'branding_watermark',
'brightness_1',
'brightness_2',
'brightness_3',
'brightness_4',
'brightness_5',
'brightness_6',
'brightness_7',
'brightness_auto',
'brightness_high',
'brightness_low',
'brightness_medium',
'broken_image',
'brush',
'bubble_chart',
'bug_report',
'build',
'burst_mode',
'business',
'business_center',
'cached',
'cake',
'call',
'call_end',
'call_made',
'call_merge',
'call_missed',
'call_missed_outgoing',
'call_received',
'call_split',
'call_to_action',
'camera',
'camera_alt',
'camera_enhance',
'camera_front',
'camera_rear',
'camera_roll',
'cancel',
'card_giftcard',
'card_membership',
'card_travel',
'casino',
'cast',
'cast_connected',
'center_focus_strong',
'center_focus_weak',
'change_history',
'chat',
'chat_bubble',
'chat_bubble_outline',
'check',
'check_box',
'check_box_outline_blank',
'check_circle',
'chevron_left',
'chevron_right',
'child_care',
'child_friendly',
'chrome_reader_mode',
'class',
'clear',
'clear_all',
'close',
'closed_caption',
'cloud',
'cloud_circle',
'cloud_done',
'cloud_download',
'cloud_off',
'cloud_queue',
'cloud_upload',
'code',
'collections',
'collections_bookmark',
'color_lens',
'colorize',
'comment',
'compare',
'compare_arrows',
'computer',
'confirmation_number',
'contact_mail',
'contact_phone',
'contacts',
'content_copy',
'content_cut',
'content_paste',
'control_point',
'control_point_duplicate',
'copyright',
'create',
'create_new_folder',
'credit_card',
'crop',
'crop_16_9',
'crop_3_2',
'crop_5_4',
'crop_7_5',
'crop_din',
'crop_free',
'crop_landscape',
'crop_original',
'crop_portrait',
'crop_rotate',
'crop_square',
'dashboard',
'data_usage',
'date_range',
'dehaze',
'delete',
'delete_forever',
'delete_sweep',
'description',
'desktop_mac',
'desktop_windows',
'details',
'developer_board',
'developer_mode',
'device_hub',
'devices',
'devices_other',
'dialer_sip',
'dialpad',
'directions',
'directions_bike',
'directions_boat',
'directions_bus',
'directions_car',
'directions_railway',
'directions_run',
'directions_subway',
'directions_transit',
'directions_walk',
'disc_full',
'dns',
'do_not_disturb',
'do_not_disturb_alt',
'do_not_disturb_off',
'do_not_disturb_on',
'dock',
'domain',
'done',
'done_all',
'donut_large',
'donut_small',
'drafts',
'drag_handle',
'drive_eta',
'dvr',
'edit',
'edit_location',
'eject',
'email',
'enhanced_encryption',
'equalizer',
'error',
'error_outline',
'euro_symbol',
'ev_station',
'event',
'event_available',
'event_busy',
'event_note',
'event_seat',
'exit_to_app',
'expand_less',
'expand_more',
'explicit',
'explore',
'exposure',
'exposure_neg_1',
'exposure_neg_2',
'exposure_plus_1',
'exposure_plus_2',
'exposure_zero',
'extension',
'face',
'fast_forward',
'fast_rewind',
'favorite',
'favorite_border',
'featured_play_list',
'featured_video',
'feedback',
'fiber_dvr',
'fiber_manual_record',
'fiber_new',
'fiber_pin',
'fiber_smart_record',
'file_download',
'file_upload',
'filter',
'filter_1',
'filter_2',
'filter_3',
'filter_4',
'filter_5',
'filter_6',
'filter_7',
'filter_8',
'filter_9',
'filter_9_plus',
'filter_b_and_w',
'filter_center_focus',
'filter_drama',
'filter_frames',
'filter_hdr',
'filter_list',
'filter_none',
'filter_tilt_shift',
'filter_vintage',
'find_in_page',
'find_replace',
'fingerprint',
'first_page',
'fitness_center',
'flag',
'flare',
'flash_auto',
'flash_off',
'flash_on',
'flight',
'flight_land',
'flight_takeoff',
'flip',
'flip_to_back',
'flip_to_front',
'folder',
'folder_open',
'folder_shared',
'folder_special',
'font_download',
'format_align_center',
'format_align_justify',
'format_align_left',
'format_align_right',
'format_bold',
'format_clear',
'format_color_fill',
'format_color_reset',
'format_color_text',
'format_indent_decrease',
'format_indent_increase',
'format_italic',
'format_line_spacing',
'format_list_bulleted',
'format_list_numbered',
'format_paint',
'format_quote',
'format_shapes',
'format_size',
'format_strikethrough',
'format_textdirection_l_to_r',
'format_textdirection_r_to_l',
'format_underlined',
'forum',
'forward',
'forward_10',
'forward_30',
'forward_5',
'free_breakfast',
'fullscreen',
'fullscreen_exit',
'functions',
'g_translate',
'gamepad',
'games',
'gavel',
'gesture',
'get_app',
'gif',
'golf_course',
'gps_fixed',
'gps_not_fixed',
'gps_off',
'grade',
'gradient',
'grain',
'graphic_eq',
'grid_off',
'grid_on',
'group',
'group_add',
'group_work',
'hd',
'hdr_off',
'hdr_on',
'hdr_strong',
'hdr_weak',
'headset',
'headset_mic',
'healing',
'hearing',
'help',
'help_outline',
'high_quality',
'highlight',
'highlight_off',
'history',
'home',
'hot_tub',
'hotel',
'hourglass_empty',
'hourglass_full',
'http',
'https',
'image',
'image_aspect_ratio',
'import_contacts',
'import_export',
'important_devices',
'inbox',
'indeterminate_check_box',
'info',
'info_outline',
'input',
'insert_chart',
'insert_comment',
'insert_drive_file',
'insert_emoticon',
'insert_invitation',
'insert_link',
'insert_photo',
'invert_colors',
'invert_colors_off',
'iso',
'keyboard',
'keyboard_arrow_down',
'keyboard_arrow_left',
'keyboard_arrow_right',
'keyboard_arrow_up',
'keyboard_backspace',
'keyboard_capslock',
'keyboard_hide',
'keyboard_return',
'keyboard_tab',
'keyboard_voice',
'kitchen',
'label',
'label_outline',
'landscape',
'language',
'laptop',
'laptop_chromebook',
'laptop_mac',
'laptop_windows',
'last_page',
'launch',
'layers',
'layers_clear',
'leak_add',
'leak_remove',
'lens',
'library_add',
'library_books',
'library_music',
'lightbulb_outline',
'line_style',
'line_weight',
'linear_scale',
'link',
'linked_camera',
'list',
'live_help',
'live_tv',
'local_activity',
'local_airport',
'local_atm',
'local_bar',
'local_cafe',
'local_car_wash',
'local_convenience_store',
'local_dining',
'local_drink',
'local_florist',
'local_gas_station',
'local_grocery_store',
'local_hospital',
'local_hotel',
'local_laundry_service',
'local_library',
'local_mall',
'local_movies',
'local_offer',
'local_parking',
'local_pharmacy',
'local_phone',
'local_pizza',
'local_play',
'local_post_office',
'local_printshop',
'local_see',
'local_shipping',
'local_taxi',
'location_city',
'location_disabled',
'location_off',
'location_on',
'location_searching',
'lock',
'lock_open',
'lock_outline',
'looks',
'looks_3',
'looks_4',
'looks_5',
'looks_6',
'looks_one',
'looks_two',
'loop',
'loupe',
'low_priority',
'loyalty',
'mail',
'mail_outline',
'map',
'markunread',
'markunread_mailbox',
'memory',
'menu',
'merge_type',
'message',
'mic',
'mic_none',
'mic_off',
'mms',
'mode_comment',
'mode_edit',
'monetization_on',
'money_off',
'monochrome_photos',
'mood',
'mood_bad',
'more',
'more_horiz',
'more_vert',
'motorcycle',
'mouse',
'move_to_inbox',
'movie',
'movie_creation',
'movie_filter',
'multiline_chart',
'music_note',
'music_video',
'my_location',
'nature',
'nature_people',
'navigate_before',
'navigate_next',
'navigation',
'near_me',
'network_cell',
'network_check',
'network_locked',
'network_wifi',
'new_releases',
'next_week',
'nfc',
'no_encryption',
'no_sim',
'not_interested',
'note',
'note_add',
'notifications',
'notifications_active',
'notifications_none',
'notifications_off',
'notifications_paused',
'offline_pin',
'ondemand_video',
'opacity',
'open_in_browser',
'open_in_new',
'open_with',
'pages',
'pageview',
'palette',
'pan_tool',
'panorama',
'panorama_fish_eye',
'panorama_horizontal',
'panorama_vertical',
'panorama_wide_angle',
'party_mode',
'pause',
'pause_circle_filled',
'pause_circle_outline',
'payment',
'people',
'people_outline',
'perm_camera_mic',
'perm_contact_calendar',
'perm_data_setting',
'perm_device_information',
'perm_identity',
'perm_media',
'perm_phone_msg',
'perm_scan_wifi',
'person',
'person_add',
'person_outline',
'person_pin',
'person_pin_circle',
'personal_video',
'pets',
'phone',
'phone_android',
'phone_bluetooth_speaker',
'phone_forwarded',
'phone_in_talk',
'phone_iphone',
'phone_locked',
'phone_missed',
'phone_paused',
'phonelink',
'phonelink_erase',
'phonelink_lock',
'phonelink_off',
'phonelink_ring',
'phonelink_setup',
'photo',
'photo_album',
'photo_camera',
'photo_filter',
'photo_library',
'photo_size_select_actual',
'photo_size_select_large',
'photo_size_select_small',
'picture_as_pdf',
'picture_in_picture',
'picture_in_picture_alt',
'pie_chart',
'pie_chart_outlined',
'pin_drop',
'place',
'play_arrow',
'play_circle_filled',
'play_circle_outline',
'play_for_work',
'playlist_add',
'playlist_add_check',
'playlist_play',
'plus_one',
'poll',
'polymer',
'pool',
'portable_wifi_off',
'portrait',
'power',
'power_input',
'power_settings_new',
'pregnant_woman',
'present_to_all',
'print',
'priority_high',
'public',
'publish',
'query_builder',
'question_answer',
'queue',
'queue_music',
'queue_play_next',
'radio',
'radio_button_checked',
'radio_button_unchecked',
'rate_review',
'receipt',
'recent_actors',
'record_voice_over',
'redeem',
'redo',
'refresh',
'remove',
'remove_circle',
'remove_circle_outline',
'remove_from_queue',
'remove_red_eye',
'remove_shopping_cart',
'reorder',
'repeat',
'repeat_one',
'replay',
'replay_10',
'replay_30',
'replay_5',
'reply',
'reply_all',
'report',
'report_problem',
'restaurant',
'restaurant_menu',
'restore',
'restore_page',
'ring_volume',
'room',
'room_service',
'rotate_90_degrees_ccw',
'rotate_left',
'rotate_right',
'rounded_corner',
'router',
'rowing',
'rss_feed',
'rv_hookup',
'satellite',
'save',
'scanner',
'schedule',
'school',
'screen_lock_landscape',
'screen_lock_portrait',
'screen_lock_rotation',
'screen_rotation',
'screen_share',
'sd_card',
'sd_storage',
'search',
'security',
'select_all',
'send',
'sentiment_dissatisfied',
'sentiment_neutral',
'sentiment_satisfied',
'sentiment_very_dissatisfied',
'sentiment_very_satisfied',
'settings',
'settings_applications',
'settings_backup_restore',
'settings_bluetooth',
'settings_brightness',
'settings_cell',
'settings_ethernet',
'settings_input_antenna',
'settings_input_component',
'settings_input_composite',
'settings_input_hdmi',
'settings_input_svideo',
'settings_overscan',
'settings_phone',
'settings_power',
'settings_remote',
'settings_system_daydream',
'settings_voice',
'share',
'shop',
'shop_two',
'shopping_basket',
'shopping_cart',
'short_text',
'show_chart',
'shuffle',
'signal_cellular_4_bar',
'signal_cellular_connected_no_internet_4_bar',
'signal_cellular_no_sim',
'signal_cellular_null',
'signal_cellular_off',
'signal_wifi_4_bar',
'signal_wifi_4_bar_lock',
'signal_wifi_off',
'sim_card',
'sim_card_alert',
'skip_next',
'skip_previous',
'slideshow',
'slow_motion_video',
'smartphone',
'smoke_free',
'smoking_rooms',
'sms',
'sms_failed',
'snooze',
'sort',
'sort_by_alpha',
'spa',
'space_bar',
'speaker',
'speaker_group',
'speaker_notes',
'speaker_notes_off',
'speaker_phone',
'spellcheck',
'star',
'star_border',
'star_half',
'stars',
'stay_current_landscape',
'stay_current_portrait',
'stay_primary_landscape',
'stay_primary_portrait',
'stop',
'stop_screen_share',
'storage',
'store',
'store_mall_directory',
'straighten',
'streetview',
'strikethrough_s',
'style',
'subdirectory_arrow_left',
'subdirectory_arrow_right',
'subject',
'subscriptions',
'subtitles',
'subway',
'supervisor_account',
'surround_sound',
'swap_calls',
'swap_horiz',
'swap_vert',
'swap_vertical_circle',
'switch_camera',
'switch_video',
'sync',
'sync_disabled',
'sync_problem',
'system_update',
'system_update_alt',
'tab',
'tab_unselected',
'tablet',
'tablet_android',
'tablet_mac',
'tag_faces',
'tap_and_play',
'terrain',
'text_fields',
'text_format',
'textsms',
'texture',
'theaters',
'thumb_down',
'thumb_up',
'thumbs_up_down',
'time_to_leave',
'timelapse',
'timeline',
'timer',
'timer_10',
'timer_3',
'timer_off',
'title',
'toc',
'today',
'toll',
'tonality',
'touch_app',
'toys',
'track_changes',
'traffic',
'train',
'tram',
'transfer_within_a_station',
'transform',
'translate',
'trending_down',
'trending_flat',
'trending_up',
'tune',
'turned_in',
'turned_in_not',
'tv',
'unarchive',
'undo',
'unfold_less',
'unfold_more',
'update',
'usb',
'verified_user',
'vertical_align_bottom',
'vertical_align_center',
'vertical_align_top',
'vibration',
'video_call',
'video_label',
'video_library',
'videocam',
'videocam_off',
'videogame_asset',
'view_agenda',
'view_array',
'view_carousel',
'view_column',
'view_comfy',
'view_compact',
'view_day',
'view_headline',
'view_list',
'view_module',
'view_quilt',
'view_stream',
'view_week',
'vignette',
'visibility',
'visibility_off',
'voice_chat',
'voicemail',
'volume_down',
'volume_mute',
'volume_off',
'volume_up',
'vpn_key',
'vpn_lock',
'wallpaper',
'warning',
'watch',
'watch_later',
'wb_auto',
'wb_cloudy',
'wb_incandescent',
'wb_iridescent',
'wb_sunny',
'wc',
'web',
'web_asset',
'weekend',
'whatshot',
'widgets',
'wifi',
'wifi_lock',
'wifi_tethering',
'work',
'wrap_text',
'youtube_searched_for',
'zoom_in',
'zoom_out',
'zoom_out_map'
];
}

View File

@@ -0,0 +1,59 @@
export class InvoiceFakeDb
{
public static invoice = {
'from' : {
'title' : 'Fuse Inc.',
'address': '2810 Country Club Road Cranford, NJ 07016',
'phone' : '+66 123 455 87',
'email' : 'hello@fuseinc.com',
'website': 'www.fuseinc.com'
},
'client' : {
'title' : 'John Doe',
'address': '9301 Wood Street Philadelphia, PA 19111',
'phone' : '+55 552 455 87',
'email' : 'johndoe@mail.com'
},
'number' : 'P9-0004',
'date' : 'Jul 19, 2015',
'dueDate' : 'Aug 24, 2015',
'services': [
{
'title' : 'Prototype & Design',
'detail' : 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus accumsan, quam sed eleifend imperdiet.',
'unit' : 'Hour',
'unitPrice': '12.00',
'quantity' : '240',
'total' : '2880'
},
{
'title' : 'Coding',
'detail' : 'Vestibulum ligula sem, rutrum et libero id, porta vehicula metus. Cras dapibus neque sit amet laoreet vestibulum.',
'unit' : 'Hour',
'unitPrice': '10.50',
'quantity' : '350',
'total' : '3675'
},
{
'title' : 'Testing',
'detail' : 'Pellentesque luctus efficitur neque in finibus. Integer ut nunc in augue maximus porttitor id id nulla. In vitae erat.',
'unit' : 'Hour',
'unitPrice': '4.00',
'quantity' : '50',
'total' : '200'
},
{
'title' : 'Documentation & Training',
'detail' : 'Pellentesque luctus efficitur neque in finibus. Integer ut nunc in augue maximus porttitor id id nulla. In vitae erat.',
'unit' : 'Hour',
'unitPrice': '6.50',
'quantity' : '260',
'total' : '1690'
}
],
'subtotal': '8445',
'tax' : '675.60',
'discount': '120.60',
'total' : '9000'
};
}

View File

@@ -0,0 +1,481 @@
export class MailFakeDb
{
public static mails = [
{
'id' : '15459251a6d6b397565',
'from' : {
'name' : 'Alice Freeman',
'avatar': 'assets/images/avatars/alice.jpg',
'email' : 'alicefreeman@creapond.com'
},
'to' : [
{
'name' : 'me',
'email': 'johndoe@creapond.com'
}
],
'subject' : 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'message' : '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce lorem diam, pulvinar id nisl non, ultrices maximus nibh. Suspendisse ut justo velit. Nullam ac ultrices risus, quis auctor orci. Vestibulum volutpat nisi et neque porta ullamcorper. Maecenas porttitor porta erat ac suscipit. Sed cursus leo ut elementum fringilla. Maecenas semper viverra erat, vel ullamcorper dui efficitur in. Vestibulum placerat imperdiet tellus, et tincidunt eros posuere eget. Proin sit amet facilisis libero. Nulla eget est ut erat aliquet rhoncus. Quisque ac urna vitae dui hendrerit sollicitudin vel id sem. </p><p> In eget ante sapien. Quisque consequat velit non ante finibus, vel placerat erat ultricies. Aliquam bibendum justo erat, ultrices vehicula dolor elementum a. Mauris eu nisl feugiat ligula molestie eleifend. Aliquam efficitur venenatis velit ac porta. Vivamus vitae pulvinar tellus. Donec odio enim, auctor eget nibh mattis, ultricies dignissim lacus. Phasellus non tincidunt dui. Nulla eu arcu lorem. </p><p> Donec non hendrerit augue, lobortis sollicitudin odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis sit amet euismod enim, eget vestibulum justo. Fusce a placerat lectus, eget feugiat purus. Cras risus ante, faucibus eget justo commodo, volutpat tempor ante. Donec sit amet leo venenatis, gravida quam sit amet, blandit dui. In quam ante, elementum ut faucibus nec, tristique vitae dui. Praesent vel erat at enim placerat luctus vel ut ipsum. In congue tempor mi, non ornare lectus condimentum at. Aenean libero diam, finibus eget sapien et, tristique fermentum lorem. </p>',
'time' : '28 Jun',
'read' : false,
'starred' : false,
'important' : true,
'hasAttachments': true,
'attachments' : [
{
'type' : 'image',
'fileName': 'flowers',
'preview' : 'assets/images/etc/flowers-thumb.jpg',
'url' : '',
'size' : '1.1Mb'
},
{
'type' : 'image',
'fileName': 'snow',
'preview' : 'assets/images/etc/snow-thumb.jpg',
'url' : '',
'size' : '380kb'
},
{
'type' : 'image',
'fileName': 'sunrise',
'preview' : 'assets/images/etc/sunrise-thumb.jpg',
'url' : 'assets/images/etc/early-sunrise.jpg',
'size' : '17Mb'
}
],
'labels' : [
1
],
'folder' : 0
},
{
'id' : '154588a0864d2881124',
'from' : {
'name' : 'Lawrence Collins',
'avatar': 'assets/images/avatars/vincent.jpg',
'email' : 'lawrencecollins@creapond.com'
},
'to' : [
{
'name' : 'me',
'email': 'johndoe@creapond.com'
}
],
'subject' : 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'message' : '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce lorem diam, pulvinar id nisl non, ultrices maximus nibh. Suspendisse ut justo velit. Nullam ac ultrices risus, quis auctor orci. Vestibulum volutpat nisi et neque porta ullamcorper. Maecenas porttitor porta erat ac suscipit. Sed cursus leo ut elementum fringilla. Maecenas semper viverra erat, vel ullamcorper dui efficitur in. Vestibulum placerat imperdiet tellus, et tincidunt eros posuere eget. Proin sit amet facilisis libero. Nulla eget est ut erat aliquet rhoncus. Quisque ac urna vitae dui hendrerit sollicitudin vel id sem. </p><p> In eget ante sapien. Quisque consequat velit non ante finibus, vel placerat erat ultricies. Aliquam bibendum justo erat, ultrices vehicula dolor elementum a. Mauris eu nisl feugiat ligula molestie eleifend. Aliquam efficitur venenatis velit ac porta. Vivamus vitae pulvinar tellus. Donec odio enim, auctor eget nibh mattis, ultricies dignissim lacus. Phasellus non tincidunt dui. Nulla eu arcu lorem. </p><p> Donec non hendrerit augue, lobortis sollicitudin odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis sit amet euismod enim, eget vestibulum justo. Fusce a placerat lectus, eget feugiat purus. Cras risus ante, faucibus eget justo commodo, volutpat tempor ante. Donec sit amet leo venenatis, gravida quam sit amet, blandit dui. In quam ante, elementum ut faucibus nec, tristique vitae dui. Praesent vel erat at enim placerat luctus vel ut ipsum. In congue tempor mi, non ornare lectus condimentum at. Aenean libero diam, finibus eget sapien et, tristique fermentum lorem. </p>',
'time' : '28 Jun',
'read' : false,
'starred' : false,
'important' : false,
'hasAttachments': false,
'labels' : [],
'folder' : 0
},
{
'id' : '15453ba60d3baa5daaf',
'from' : {
'name' : 'Judith Burton',
'avatar': 'assets/images/avatars/joyce.jpg',
'email' : 'judithburton@creapond.com'
},
'to' : [
{
'name' : 'me',
'email': 'johndoe@creapond.com'
}
],
'subject' : 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'message' : '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce lorem diam, pulvinar id nisl non, ultrices maximus nibh. Suspendisse ut justo velit. Nullam ac ultrices risus, quis auctor orci. Vestibulum volutpat nisi et neque porta ullamcorper. Maecenas porttitor porta erat ac suscipit. Sed cursus leo ut elementum fringilla. Maecenas semper viverra erat, vel ullamcorper dui efficitur in. Vestibulum placerat imperdiet tellus, et tincidunt eros posuere eget. Proin sit amet facilisis libero. Nulla eget est ut erat aliquet rhoncus. Quisque ac urna vitae dui hendrerit sollicitudin vel id sem. </p><p> In eget ante sapien. Quisque consequat velit non ante finibus, vel placerat erat ultricies. Aliquam bibendum justo erat, ultrices vehicula dolor elementum a. Mauris eu nisl feugiat ligula molestie eleifend. Aliquam efficitur venenatis velit ac porta. Vivamus vitae pulvinar tellus. Donec odio enim, auctor eget nibh mattis, ultricies dignissim lacus. Phasellus non tincidunt dui. Nulla eu arcu lorem. </p><p> Donec non hendrerit augue, lobortis sollicitudin odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis sit amet euismod enim, eget vestibulum justo. Fusce a placerat lectus, eget feugiat purus. Cras risus ante, faucibus eget justo commodo, volutpat tempor ante. Donec sit amet leo venenatis, gravida quam sit amet, blandit dui. In quam ante, elementum ut faucibus nec, tristique vitae dui. Praesent vel erat at enim placerat luctus vel ut ipsum. In congue tempor mi, non ornare lectus condimentum at. Aenean libero diam, finibus eget sapien et, tristique fermentum lorem. </p>',
'time' : '28 Jun',
'read' : true,
'starred' : false,
'important' : false,
'hasAttachments': false,
'labels' : [
3,
2
],
'folder' : 0
},
{
'id' : '15453a06c08fb021776',
'from' : {
'name' : 'Danielle Obrien',
'avatar': 'assets/images/avatars/danielle.jpg',
'email' : 'danielleobrien@creapond.com'
},
'to' : [
{
'name' : 'me',
'email': 'johndoe@creapond.com'
}
],
'subject' : 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'message' : '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce lorem diam, pulvinar id nisl non, ultrices maximus nibh. Suspendisse ut justo velit. Nullam ac ultrices risus, quis auctor orci. Vestibulum volutpat nisi et neque porta ullamcorper. Maecenas porttitor porta erat ac suscipit. Sed cursus leo ut elementum fringilla. Maecenas semper viverra erat, vel ullamcorper dui efficitur in. Vestibulum placerat imperdiet tellus, et tincidunt eros posuere eget. Proin sit amet facilisis libero. Nulla eget est ut erat aliquet rhoncus. Quisque ac urna vitae dui hendrerit sollicitudin vel id sem. </p><p> In eget ante sapien. Quisque consequat velit non ante finibus, vel placerat erat ultricies. Aliquam bibendum justo erat, ultrices vehicula dolor elementum a. Mauris eu nisl feugiat ligula molestie eleifend. Aliquam efficitur venenatis velit ac porta. Vivamus vitae pulvinar tellus. Donec odio enim, auctor eget nibh mattis, ultricies dignissim lacus. Phasellus non tincidunt dui. Nulla eu arcu lorem. </p><p> Donec non hendrerit augue, lobortis sollicitudin odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis sit amet euismod enim, eget vestibulum justo. Fusce a placerat lectus, eget feugiat purus. Cras risus ante, faucibus eget justo commodo, volutpat tempor ante. Donec sit amet leo venenatis, gravida quam sit amet, blandit dui. In quam ante, elementum ut faucibus nec, tristique vitae dui. Praesent vel erat at enim placerat luctus vel ut ipsum. In congue tempor mi, non ornare lectus condimentum at. Aenean libero diam, finibus eget sapien et, tristique fermentum lorem. </p>',
'time' : '28 Jun',
'read' : true,
'starred' : true,
'important' : false,
'hasAttachments': false,
'labels' : [
1,
3
],
'folder' : 0
},
{
'id' : '154537435d5b32bf11a',
'from' : {
'name' : 'Brian Flores',
'avatar': '',
'email' : 'brianflores@creapond.com'
},
'to' : [
{
'name' : 'me',
'email': 'johndoe@creapond.com'
}
],
'subject' : 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'message' : '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce lorem diam, pulvinar id nisl non, ultrices maximus nibh. Suspendisse ut justo velit. Nullam ac ultrices risus, quis auctor orci. Vestibulum volutpat nisi et neque porta ullamcorper. Maecenas porttitor porta erat ac suscipit. Sed cursus leo ut elementum fringilla. Maecenas semper viverra erat, vel ullamcorper dui efficitur in. Vestibulum placerat imperdiet tellus, et tincidunt eros posuere eget. Proin sit amet facilisis libero. Nulla eget est ut erat aliquet rhoncus. Quisque ac urna vitae dui hendrerit sollicitudin vel id sem. </p><p> In eget ante sapien. Quisque consequat velit non ante finibus, vel placerat erat ultricies. Aliquam bibendum justo erat, ultrices vehicula dolor elementum a. Mauris eu nisl feugiat ligula molestie eleifend. Aliquam efficitur venenatis velit ac porta. Vivamus vitae pulvinar tellus. Donec odio enim, auctor eget nibh mattis, ultricies dignissim lacus. Phasellus non tincidunt dui. Nulla eu arcu lorem. </p><p> Donec non hendrerit augue, lobortis sollicitudin odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis sit amet euismod enim, eget vestibulum justo. Fusce a placerat lectus, eget feugiat purus. Cras risus ante, faucibus eget justo commodo, volutpat tempor ante. Donec sit amet leo venenatis, gravida quam sit amet, blandit dui. In quam ante, elementum ut faucibus nec, tristique vitae dui. Praesent vel erat at enim placerat luctus vel ut ipsum. In congue tempor mi, non ornare lectus condimentum at. Aenean libero diam, finibus eget sapien et, tristique fermentum lorem. </p>',
'time' : '26 Jun',
'read' : true,
'starred' : false,
'important' : false,
'hasAttachments': false,
'labels' : [],
'folder' : 0
},
{
'id' : '1544e43dcdae6ebf876',
'from' : {
'name' : 'Charles Kim',
'avatar': 'assets/images/avatars/garry.jpg',
'email' : 'charleskim@creapond.com'
},
'to' : [
{
'name' : 'me',
'email': 'johndoe@creapond.com'
}
],
'subject' : 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'message' : '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce lorem diam, pulvinar id nisl non, ultrices maximus nibh. Suspendisse ut justo velit. Nullam ac ultrices risus, quis auctor orci. Vestibulum volutpat nisi et neque porta ullamcorper. Maecenas porttitor porta erat ac suscipit. Sed cursus leo ut elementum fringilla. Maecenas semper viverra erat, vel ullamcorper dui efficitur in. Vestibulum placerat imperdiet tellus, et tincidunt eros posuere eget. Proin sit amet facilisis libero. Nulla eget est ut erat aliquet rhoncus. Quisque ac urna vitae dui hendrerit sollicitudin vel id sem. </p><p> In eget ante sapien. Quisque consequat velit non ante finibus, vel placerat erat ultricies. Aliquam bibendum justo erat, ultrices vehicula dolor elementum a. Mauris eu nisl feugiat ligula molestie eleifend. Aliquam efficitur venenatis velit ac porta. Vivamus vitae pulvinar tellus. Donec odio enim, auctor eget nibh mattis, ultricies dignissim lacus. Phasellus non tincidunt dui. Nulla eu arcu lorem. </p><p> Donec non hendrerit augue, lobortis sollicitudin odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis sit amet euismod enim, eget vestibulum justo. Fusce a placerat lectus, eget feugiat purus. Cras risus ante, faucibus eget justo commodo, volutpat tempor ante. Donec sit amet leo venenatis, gravida quam sit amet, blandit dui. In quam ante, elementum ut faucibus nec, tristique vitae dui. Praesent vel erat at enim placerat luctus vel ut ipsum. In congue tempor mi, non ornare lectus condimentum at. Aenean libero diam, finibus eget sapien et, tristique fermentum lorem. </p>',
'time' : '18 Jun',
'read' : true,
'starred' : false,
'important' : true,
'hasAttachments': false,
'labels' : [
2
],
'folder' : 0
},
{
'id' : '1543ee3a5b43e0f9f45',
'from' : {
'name' : 'Patricia White',
'avatar': '',
'email' : 'patriciawhite@creapond.com'
},
'to' : [
{
'name' : 'me',
'email': 'johndoe@creapond.com'
}
],
'subject' : 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'message' : '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce lorem diam, pulvinar id nisl non, ultrices maximus nibh. Suspendisse ut justo velit. Nullam ac ultrices risus, quis auctor orci. Vestibulum volutpat nisi et neque porta ullamcorper. Maecenas porttitor porta erat ac suscipit. Sed cursus leo ut elementum fringilla. Maecenas semper viverra erat, vel ullamcorper dui efficitur in. Vestibulum placerat imperdiet tellus, et tincidunt eros posuere eget. Proin sit amet facilisis libero. Nulla eget est ut erat aliquet rhoncus. Quisque ac urna vitae dui hendrerit sollicitudin vel id sem. </p><p> In eget ante sapien. Quisque consequat velit non ante finibus, vel placerat erat ultricies. Aliquam bibendum justo erat, ultrices vehicula dolor elementum a. Mauris eu nisl feugiat ligula molestie eleifend. Aliquam efficitur venenatis velit ac porta. Vivamus vitae pulvinar tellus. Donec odio enim, auctor eget nibh mattis, ultricies dignissim lacus. Phasellus non tincidunt dui. Nulla eu arcu lorem. </p><p> Donec non hendrerit augue, lobortis sollicitudin odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis sit amet euismod enim, eget vestibulum justo. Fusce a placerat lectus, eget feugiat purus. Cras risus ante, faucibus eget justo commodo, volutpat tempor ante. Donec sit amet leo venenatis, gravida quam sit amet, blandit dui. In quam ante, elementum ut faucibus nec, tristique vitae dui. Praesent vel erat at enim placerat luctus vel ut ipsum. In congue tempor mi, non ornare lectus condimentum at. Aenean libero diam, finibus eget sapien et, tristique fermentum lorem. </p>',
'time' : '15 Jun',
'read' : true,
'starred' : false,
'important' : false,
'hasAttachments': false,
'labels' : [],
'folder' : 0
},
{
'id' : '1543cc4515df3146112',
'from' : {
'name' : 'Juan Carpenter',
'avatar': 'assets/images/avatars/james.jpg',
'email' : 'juancarpenter@creapond.com'
},
'to' : [
{
'name' : 'me',
'email': 'johndoe@creapond.com'
}
],
'subject' : 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'message' : '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce lorem diam, pulvinar id nisl non, ultrices maximus nibh. Suspendisse ut justo velit. Nullam ac ultrices risus, quis auctor orci. Vestibulum volutpat nisi et neque porta ullamcorper. Maecenas porttitor porta erat ac suscipit. Sed cursus leo ut elementum fringilla. Maecenas semper viverra erat, vel ullamcorper dui efficitur in. Vestibulum placerat imperdiet tellus, et tincidunt eros posuere eget. Proin sit amet facilisis libero. Nulla eget est ut erat aliquet rhoncus. Quisque ac urna vitae dui hendrerit sollicitudin vel id sem. </p><p> In eget ante sapien. Quisque consequat velit non ante finibus, vel placerat erat ultricies. Aliquam bibendum justo erat, ultrices vehicula dolor elementum a. Mauris eu nisl feugiat ligula molestie eleifend. Aliquam efficitur venenatis velit ac porta. Vivamus vitae pulvinar tellus. Donec odio enim, auctor eget nibh mattis, ultricies dignissim lacus. Phasellus non tincidunt dui. Nulla eu arcu lorem. </p><p> Donec non hendrerit augue, lobortis sollicitudin odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis sit amet euismod enim, eget vestibulum justo. Fusce a placerat lectus, eget feugiat purus. Cras risus ante, faucibus eget justo commodo, volutpat tempor ante. Donec sit amet leo venenatis, gravida quam sit amet, blandit dui. In quam ante, elementum ut faucibus nec, tristique vitae dui. Praesent vel erat at enim placerat luctus vel ut ipsum. In congue tempor mi, non ornare lectus condimentum at. Aenean libero diam, finibus eget sapien et, tristique fermentum lorem. </p>',
'time' : '11 Jun',
'read' : true,
'starred' : false,
'important' : false,
'hasAttachments': false,
'labels' : [],
'folder' : 0
},
{
'id' : '154398a4770d7aaf9a2',
'from' : {
'name' : 'Maria Gilbert',
'avatar': 'assets/images/avatars/danielle.jpg',
'email' : 'mariagilbert@creapond.com'
},
'to' : [
{
'name' : 'me',
'email': 'johndoe@creapond.com'
}
],
'subject' : 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'message' : '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce lorem diam, pulvinar id nisl non, ultrices maximus nibh. Suspendisse ut justo velit. Nullam ac ultrices risus, quis auctor orci. Vestibulum volutpat nisi et neque porta ullamcorper. Maecenas porttitor porta erat ac suscipit. Sed cursus leo ut elementum fringilla. Maecenas semper viverra erat, vel ullamcorper dui efficitur in. Vestibulum placerat imperdiet tellus, et tincidunt eros posuere eget. Proin sit amet facilisis libero. Nulla eget est ut erat aliquet rhoncus. Quisque ac urna vitae dui hendrerit sollicitudin vel id sem. </p><p> In eget ante sapien. Quisque consequat velit non ante finibus, vel placerat erat ultricies. Aliquam bibendum justo erat, ultrices vehicula dolor elementum a. Mauris eu nisl feugiat ligula molestie eleifend. Aliquam efficitur venenatis velit ac porta. Vivamus vitae pulvinar tellus. Donec odio enim, auctor eget nibh mattis, ultricies dignissim lacus. Phasellus non tincidunt dui. Nulla eu arcu lorem. </p><p> Donec non hendrerit augue, lobortis sollicitudin odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis sit amet euismod enim, eget vestibulum justo. Fusce a placerat lectus, eget feugiat purus. Cras risus ante, faucibus eget justo commodo, volutpat tempor ante. Donec sit amet leo venenatis, gravida quam sit amet, blandit dui. In quam ante, elementum ut faucibus nec, tristique vitae dui. Praesent vel erat at enim placerat luctus vel ut ipsum. In congue tempor mi, non ornare lectus condimentum at. Aenean libero diam, finibus eget sapien et, tristique fermentum lorem. </p>',
'time' : '5 Jun',
'read' : true,
'starred' : false,
'important' : false,
'hasAttachments': false,
'labels' : [],
'folder' : 0
},
{
'id' : '15438351f87dcd68567',
'from' : {
'name' : 'Tammy Brooks',
'avatar': '',
'email' : 'tammybrooks@creapond.com'
},
'to' : [
{
'name' : 'me',
'email': 'johndoe@creapond.com'
}
],
'subject' : 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'message' : '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce lorem diam, pulvinar id nisl non, ultrices maximus nibh. Suspendisse ut justo velit. Nullam ac ultrices risus, quis auctor orci. Vestibulum volutpat nisi et neque porta ullamcorper. Maecenas porttitor porta erat ac suscipit. Sed cursus leo ut elementum fringilla. Maecenas semper viverra erat, vel ullamcorper dui efficitur in. Vestibulum placerat imperdiet tellus, et tincidunt eros posuere eget. Proin sit amet facilisis libero. Nulla eget est ut erat aliquet rhoncus. Quisque ac urna vitae dui hendrerit sollicitudin vel id sem. </p><p> In eget ante sapien. Quisque consequat velit non ante finibus, vel placerat erat ultricies. Aliquam bibendum justo erat, ultrices vehicula dolor elementum a. Mauris eu nisl feugiat ligula molestie eleifend. Aliquam efficitur venenatis velit ac porta. Vivamus vitae pulvinar tellus. Donec odio enim, auctor eget nibh mattis, ultricies dignissim lacus. Phasellus non tincidunt dui. Nulla eu arcu lorem. </p><p> Donec non hendrerit augue, lobortis sollicitudin odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis sit amet euismod enim, eget vestibulum justo. Fusce a placerat lectus, eget feugiat purus. Cras risus ante, faucibus eget justo commodo, volutpat tempor ante. Donec sit amet leo venenatis, gravida quam sit amet, blandit dui. In quam ante, elementum ut faucibus nec, tristique vitae dui. Praesent vel erat at enim placerat luctus vel ut ipsum. In congue tempor mi, non ornare lectus condimentum at. Aenean libero diam, finibus eget sapien et, tristique fermentum lorem. </p>',
'time' : '1 Jun',
'read' : true,
'starred' : false,
'important' : false,
'hasAttachments': false,
'labels' : [],
'folder' : 0
},
{
'id' : '1542d75d929a603125',
'from' : {
'name' : 'Kathy Price',
'avatar': '',
'email' : 'kathyprice@creapond.com'
},
'to' : [
{
'name' : 'me',
'email': 'johndoe@creapond.com'
}
],
'subject' : 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'message' : '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce lorem diam, pulvinar id nisl non, ultrices maximus nibh. Suspendisse ut justo velit. Nullam ac ultrices risus, quis auctor orci. Vestibulum volutpat nisi et neque porta ullamcorper. Maecenas porttitor porta erat ac suscipit. Sed cursus leo ut elementum fringilla. Maecenas semper viverra erat, vel ullamcorper dui efficitur in. Vestibulum placerat imperdiet tellus, et tincidunt eros posuere eget. Proin sit amet facilisis libero. Nulla eget est ut erat aliquet rhoncus. Quisque ac urna vitae dui hendrerit sollicitudin vel id sem. </p><p> In eget ante sapien. Quisque consequat velit non ante finibus, vel placerat erat ultricies. Aliquam bibendum justo erat, ultrices vehicula dolor elementum a. Mauris eu nisl feugiat ligula molestie eleifend. Aliquam efficitur venenatis velit ac porta. Vivamus vitae pulvinar tellus. Donec odio enim, auctor eget nibh mattis, ultricies dignissim lacus. Phasellus non tincidunt dui. Nulla eu arcu lorem. </p><p> Donec non hendrerit augue, lobortis sollicitudin odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis sit amet euismod enim, eget vestibulum justo. Fusce a placerat lectus, eget feugiat purus. Cras risus ante, faucibus eget justo commodo, volutpat tempor ante. Donec sit amet leo venenatis, gravida quam sit amet, blandit dui. In quam ante, elementum ut faucibus nec, tristique vitae dui. Praesent vel erat at enim placerat luctus vel ut ipsum. In congue tempor mi, non ornare lectus condimentum at. Aenean libero diam, finibus eget sapien et, tristique fermentum lorem. </p> ',
'time' : '1 Jun',
'read' : true,
'starred' : false,
'important' : false,
'hasAttachments': false,
'labels' : [],
'folder' : 0
},
{
'id' : '1541ca7af66da284177',
'from' : {
'name' : 'Alan Coleman',
'avatar': '',
'email' : 'alancoleman@creapond.com'
},
'to' : [
{
'name' : 'me',
'email': 'johndoe@creapond.com'
}
],
'subject' : 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'message' : '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce lorem diam, pulvinar id nisl non, ultrices maximus nibh. Suspendisse ut justo velit. Nullam ac ultrices risus, quis auctor orci. Vestibulum volutpat nisi et neque porta ullamcorper. Maecenas porttitor porta erat ac suscipit. Sed cursus leo ut elementum fringilla. Maecenas semper viverra erat, vel ullamcorper dui efficitur in. Vestibulum placerat imperdiet tellus, et tincidunt eros posuere eget. Proin sit amet facilisis libero. Nulla eget est ut erat aliquet rhoncus. Quisque ac urna vitae dui hendrerit sollicitudin vel id sem. </p><p> In eget ante sapien. Quisque consequat velit non ante finibus, vel placerat erat ultricies. Aliquam bibendum justo erat, ultrices vehicula dolor elementum a. Mauris eu nisl feugiat ligula molestie eleifend. Aliquam efficitur venenatis velit ac porta. Vivamus vitae pulvinar tellus. Donec odio enim, auctor eget nibh mattis, ultricies dignissim lacus. Phasellus non tincidunt dui. Nulla eu arcu lorem. </p><p> Donec non hendrerit augue, lobortis sollicitudin odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis sit amet euismod enim, eget vestibulum justo. Fusce a placerat lectus, eget feugiat purus. Cras risus ante, faucibus eget justo commodo, volutpat tempor ante. Donec sit amet leo venenatis, gravida quam sit amet, blandit dui. In quam ante, elementum ut faucibus nec, tristique vitae dui. Praesent vel erat at enim placerat luctus vel ut ipsum. In congue tempor mi, non ornare lectus condimentum at. Aenean libero diam, finibus eget sapien et, tristique fermentum lorem. </p> ',
'time' : '28 June',
'read' : true,
'starred' : false,
'important' : false,
'hasAttachments': false,
'labels' : [],
'folder' : 0
},
{
'id' : '154297167e781781745',
'from' : {
'name' : 'Thomas Silva',
'avatar': '',
'email' : 'thomassilva@creapond.com'
},
'to' : [
{
'name' : 'me',
'email': 'johndoe@creapond.com'
}
],
'subject' : 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'message' : '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce lorem diam, pulvinar id nisl non, ultrices maximus nibh. Suspendisse ut justo velit. Nullam ac ultrices risus, quis auctor orci. Vestibulum volutpat nisi et neque porta ullamcorper. Maecenas porttitor porta erat ac suscipit. Sed cursus leo ut elementum fringilla. Maecenas semper viverra erat, vel ullamcorper dui efficitur in. Vestibulum placerat imperdiet tellus, et tincidunt eros posuere eget. Proin sit amet facilisis libero. Nulla eget est ut erat aliquet rhoncus. Quisque ac urna vitae dui hendrerit sollicitudin vel id sem. </p><p> In eget ante sapien. Quisque consequat velit non ante finibus, vel placerat erat ultricies. Aliquam bibendum justo erat, ultrices vehicula dolor elementum a. Mauris eu nisl feugiat ligula molestie eleifend. Aliquam efficitur venenatis velit ac porta. Vivamus vitae pulvinar tellus. Donec odio enim, auctor eget nibh mattis, ultricies dignissim lacus. Phasellus non tincidunt dui. Nulla eu arcu lorem. </p><p> Donec non hendrerit augue, lobortis sollicitudin odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis sit amet euismod enim, eget vestibulum justo. Fusce a placerat lectus, eget feugiat purus. Cras risus ante, faucibus eget justo commodo, volutpat tempor ante. Donec sit amet leo venenatis, gravida quam sit amet, blandit dui. In quam ante, elementum ut faucibus nec, tristique vitae dui. Praesent vel erat at enim placerat luctus vel ut ipsum. In congue tempor mi, non ornare lectus condimentum at. Aenean libero diam, finibus eget sapien et, tristique fermentum lorem. </p> ',
'time' : '16 Jun',
'read' : true,
'starred' : false,
'important' : false,
'hasAttachments': false,
'labels' : [],
'folder' : 0
},
{
'id' : '15427f4c1b7f3953234',
'from' : {
'name' : 'Jessica Robertson',
'avatar': '',
'email' : 'jessicarobertson@creapond.com'
},
'to' : [
{
'name' : 'me',
'email': 'johndoe@creapond.com'
}
],
'subject' : 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'message' : '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce lorem diam, pulvinar id nisl non, ultrices maximus nibh. Suspendisse ut justo velit. Nullam ac ultrices risus, quis auctor orci. Vestibulum volutpat nisi et neque porta ullamcorper. Maecenas porttitor porta erat ac suscipit. Sed cursus leo ut elementum fringilla. Maecenas semper viverra erat, vel ullamcorper dui efficitur in. Vestibulum placerat imperdiet tellus, et tincidunt eros posuere eget. Proin sit amet facilisis libero. Nulla eget est ut erat aliquet rhoncus. Quisque ac urna vitae dui hendrerit sollicitudin vel id sem. </p><p> In eget ante sapien. Quisque consequat velit non ante finibus, vel placerat erat ultricies. Aliquam bibendum justo erat, ultrices vehicula dolor elementum a. Mauris eu nisl feugiat ligula molestie eleifend. Aliquam efficitur venenatis velit ac porta. Vivamus vitae pulvinar tellus. Donec odio enim, auctor eget nibh mattis, ultricies dignissim lacus. Phasellus non tincidunt dui. Nulla eu arcu lorem. </p><p> Donec non hendrerit augue, lobortis sollicitudin odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis sit amet euismod enim, eget vestibulum justo. Fusce a placerat lectus, eget feugiat purus. Cras risus ante, faucibus eget justo commodo, volutpat tempor ante. Donec sit amet leo venenatis, gravida quam sit amet, blandit dui. In quam ante, elementum ut faucibus nec, tristique vitae dui. Praesent vel erat at enim placerat luctus vel ut ipsum. In congue tempor mi, non ornare lectus condimentum at. Aenean libero diam, finibus eget sapien et, tristique fermentum lorem. </p> ',
'time' : '19 May',
'read' : true,
'starred' : false,
'important' : false,
'hasAttachments': false,
'labels' : [],
'folder' : 3
},
{
'id' : '154204e45a59b168453',
'from' : {
'name' : 'John Palmer',
'avatar': '',
'email' : 'johnpalmer@creapond.com'
},
'to' : [
{
'name' : 'me',
'email': 'johndoe@creapond.com'
}
],
'subject' : 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'message' : '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce lorem diam, pulvinar id nisl non, ultrices maximus nibh. Suspendisse ut justo velit. Nullam ac ultrices risus, quis auctor orci. Vestibulum volutpat nisi et neque porta ullamcorper. Maecenas porttitor porta erat ac suscipit. Sed cursus leo ut elementum fringilla. Maecenas semper viverra erat, vel ullamcorper dui efficitur in. Vestibulum placerat imperdiet tellus, et tincidunt eros posuere eget. Proin sit amet facilisis libero. Nulla eget est ut erat aliquet rhoncus. Quisque ac urna vitae dui hendrerit sollicitudin vel id sem. </p><p> In eget ante sapien. Quisque consequat velit non ante finibus, vel placerat erat ultricies. Aliquam bibendum justo erat, ultrices vehicula dolor elementum a. Mauris eu nisl feugiat ligula molestie eleifend. Aliquam efficitur venenatis velit ac porta. Vivamus vitae pulvinar tellus. Donec odio enim, auctor eget nibh mattis, ultricies dignissim lacus. Phasellus non tincidunt dui. Nulla eu arcu lorem. </p><p> Donec non hendrerit augue, lobortis sollicitudin odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis sit amet euismod enim, eget vestibulum justo. Fusce a placerat lectus, eget feugiat purus. Cras risus ante, faucibus eget justo commodo, volutpat tempor ante. Donec sit amet leo venenatis, gravida quam sit amet, blandit dui. In quam ante, elementum ut faucibus nec, tristique vitae dui. Praesent vel erat at enim placerat luctus vel ut ipsum. In congue tempor mi, non ornare lectus condimentum at. Aenean libero diam, finibus eget sapien et, tristique fermentum lorem. </p> ',
'time' : '8 May',
'read' : true,
'starred' : false,
'important' : false,
'hasAttachments': false,
'labels' : [],
'folder' : 3
},
{
'id' : '1541dd1e05dfc439216',
'from' : {
'name' : 'David Butler',
'avatar': '',
'email' : 'davidbutler@creapond.com'
},
'to' : [
{
'name' : 'me',
'email': 'johndoe@creapond.com'
}
],
'subject' : 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'message' : '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce lorem diam, pulvinar id nisl non, ultrices maximus nibh. Suspendisse ut justo velit. Nullam ac ultrices risus, quis auctor orci. Vestibulum volutpat nisi et neque porta ullamcorper. Maecenas porttitor porta erat ac suscipit. Sed cursus leo ut elementum fringilla. Maecenas semper viverra erat, vel ullamcorper dui efficitur in. Vestibulum placerat imperdiet tellus, et tincidunt eros posuere eget. Proin sit amet facilisis libero. Nulla eget est ut erat aliquet rhoncus. Quisque ac urna vitae dui hendrerit sollicitudin vel id sem. </p><p> In eget ante sapien. Quisque consequat velit non ante finibus, vel placerat erat ultricies. Aliquam bibendum justo erat, ultrices vehicula dolor elementum a. Mauris eu nisl feugiat ligula molestie eleifend. Aliquam efficitur venenatis velit ac porta. Vivamus vitae pulvinar tellus. Donec odio enim, auctor eget nibh mattis, ultricies dignissim lacus. Phasellus non tincidunt dui. Nulla eu arcu lorem. </p><p> Donec non hendrerit augue, lobortis sollicitudin odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis sit amet euismod enim, eget vestibulum justo. Fusce a placerat lectus, eget feugiat purus. Cras risus ante, faucibus eget justo commodo, volutpat tempor ante. Donec sit amet leo venenatis, gravida quam sit amet, blandit dui. In quam ante, elementum ut faucibus nec, tristique vitae dui. Praesent vel erat at enim placerat luctus vel ut ipsum. In congue tempor mi, non ornare lectus condimentum at. Aenean libero diam, finibus eget sapien et, tristique fermentum lorem. </p> ',
'time' : '7 May',
'read' : true,
'starred' : false,
'important' : false,
'hasAttachments': false,
'labels' : [],
'folder' : 3
}
];
public static folders = [
{
'id' : 0,
'handle': 'inbox',
'title' : 'Inbox',
'icon' : 'inbox'
},
{
'id' : 1,
'handle': 'sent',
'title' : 'Sent',
'icon' : 'send'
},
{
'id' : 2,
'handle': 'drafts',
'title' : 'Drafts',
'icon' : 'email_open'
},
{
'id' : 3,
'handle': 'spam',
'title' : 'Spam',
'icon' : 'error'
},
{
'id' : 4,
'handle': 'trash',
'title' : 'Trash',
'icon' : 'delete'
}
];
public static filters = [
{
'id' : 0,
'handle': 'starred',
'title' : 'Starred',
'icon' : 'star'
},
{
'id' : 1,
'handle': 'important',
'title' : 'Important',
'icon' : 'label'
}
];
public static labels = [
{
'id' : 0,
'handle': 'note',
'title' : 'Note',
'color' : '#7cb342'
},
{
'id' : 1,
'handle': 'paypal',
'title' : 'Paypal',
'color' : '#d84315'
},
{
'id' : 2,
'handle': 'invoice',
'title' : 'Invoice',
'color' : '#607d8b'
},
{
'id' : 3,
'handle': 'amazon',
'title' : 'Amazon',
'color' : '#03a9f4'
}
];
}

View File

@@ -0,0 +1,360 @@
export class ProfileFakeDb
{
public static timeline = {
activities: [
{
'user' : {
'name' : 'Alice Freeman',
'avatar': 'assets/images/avatars/alice.jpg'
},
'message': 'started following you.',
'time' : '13 mins. ago'
},
{
'user' : {
'name' : 'Andrew Green',
'avatar': 'assets/images/avatars/andrew.jpg'
},
'message': 'sent you a message.',
'time' : 'June 10,2015'
},
{
'user' : {
'name' : 'Garry Newman',
'avatar': 'assets/images/avatars/garry.jpg'
},
'message': 'shared a public post with your group.',
'time' : 'June 9,2015'
},
{
'user' : {
'name' : 'Carl Henderson',
'avatar': 'assets/images/avatars/carl.jpg'
},
'message': 'wants to play Fallout Shelter with you.',
'time' : 'June 8,2015'
},
{
'user' : {
'name' : 'Jane Dean',
'avatar': 'assets/images/avatars/jane.jpg'
},
'message': 'started following you.',
'time' : 'June 7,2015'
},
{
'user' : {
'name' : 'Juan Carpenter',
'avatar': 'assets/images/avatars/james.jpg'
},
'message': 'sent you a message.',
'time' : 'June 6,2015'
},
{
'user' : {
'name' : 'Judith Burton',
'avatar': 'assets/images/avatars/joyce.jpg'
},
'message': 'shared a photo with you.',
'time' : 'June 5,2015'
},
{
'user' : {
'name' : 'Vincent Munoz',
'avatar': 'assets/images/avatars/vincent.jpg'
},
'message': 'shared a photo with you.',
'time' : 'June 4,2015'
}
],
posts : [
{
'user' : {
'name' : 'Garry Newman',
'avatar': 'assets/images/avatars/garry.jpg'
},
'message' : 'Remember the place we were talking about the other night? Found it!',
'time' : '32 minutes ago',
'type' : 'post',
'like' : 5,
'share' : 21,
'media' : {
'type' : 'image',
'preview': 'assets/images/etc/early-sunrise.jpg'
},
'comments': [
{
'user' : {
'name' : 'Alice Freeman',
'avatar': 'assets/images/avatars/alice.jpg'
},
'time' : 'June 10, 2015',
'message': 'Thats a wonderful place. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce et eleifend ligula. Fusce posuere in sapien ac facilisis. Etiam sit amet justo non felis ornare feugiat.'
}
]
},
{
'user' : {
'name' : 'Andrew Green',
'avatar': 'assets/images/avatars/andrew.jpg'
},
'message' : 'Hey, man! Check this, its pretty awesome!',
'time' : 'June 12, 2015',
'type' : 'article',
'like' : 98,
'share' : 6,
'article' : {
'title' : 'The Fallout 4 Pip-Boy Edition Is Back In Stock Now',
'subtitle': 'Kotaku',
'excerpt' : 'The Fallout 4 Pip-Boy edition is back in stock at Gamestop, for all 3 platforms. Additionally, Walmart also has it in stock for the PS4 and Xbox One as of this writing, as does Best Buy.',
'media' : {
'type' : 'image',
'preview': 'assets/images/etc/fallout.jpg'
}
},
'comments': [
{
'user' : {
'name' : 'Alice Freeman',
'avatar': 'assets/images/avatars/alice.jpg'
},
'time' : 'June 10, 2015',
'message': 'Thats a wonderful place. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce et eleifend ligula. Fusce posuere in sapien ac facilisis. Etiam sit amet justo non felis ornare feugiat.'
}
]
},
{
'user' : {
'name' : 'Carl Henderson',
'avatar': 'assets/images/avatars/carl.jpg'
},
'message': 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce et eleifend ligula. Fusce posuere in sapien ac facilisis. Etiam sit amet justo non felis ornare feugiat. Aenean lorem ex, ultrices sit amet ligula sed...',
'time' : 'June 10, 2015',
'type' : 'something',
'like' : 4,
'share' : 1
}
]
};
public static photosVideos = [
{
'name' : 'June 2015',
'info' : '5 Photos',
'media': [
{
'type' : 'photo',
'title' : 'Mountain Sunset',
'preview': 'assets/images/etc/mountain-sunset.jpg'
},
{
'type' : 'photo',
'title' : 'Mountain Lake',
'preview': 'assets/images/etc/mountain-lake.jpg'
},
{
'type' : 'photo',
'title' : 'Hot air balloons',
'preview': 'assets/images/etc/air-balloons.jpg'
},
{
'type' : 'photo',
'title' : 'Cactus',
'preview': 'assets/images/etc/cactus.jpg'
},
{
'type' : 'photo',
'title' : 'Road Trip',
'preview': 'assets/images/etc/road-trip.jpg'
}
]
},
{
'name' : 'May 2015',
'info' : '7 Photos, 3 Videos',
'media': [
{
'type' : 'photo',
'title' : 'Mountain Sunset',
'preview': 'assets/images/etc/mountain-sunset.jpg'
},
{
'type' : 'photo',
'title' : 'Mountain Lake',
'preview': 'assets/images/etc/mountain-lake.jpg'
},
{
'type' : 'photo',
'title' : 'Hot air balloons',
'preview': 'assets/images/etc/air-balloons.jpg'
},
{
'type' : 'photo',
'title' : 'Cactus',
'preview': 'assets/images/etc/cactus.jpg'
},
{
'type' : 'photo',
'title' : 'Road Trip',
'preview': 'assets/images/etc/road-trip.jpg'
},
{
'type' : 'photo',
'title' : 'Mountain Sunset',
'preview': 'assets/images/etc/mountain-sunset.jpg'
},
{
'type' : 'photo',
'title' : 'Mountain Lake',
'preview': 'assets/images/etc/mountain-lake.jpg'
},
{
'type' : 'photo',
'title' : 'Hot air balloons',
'preview': 'assets/images/etc/air-balloons.jpg'
},
{
'type' : 'photo',
'title' : 'Cactus',
'preview': 'assets/images/etc/cactus.jpg'
},
{
'type' : 'photo',
'title' : 'Road Trip',
'preview': 'assets/images/etc/road-trip.jpg'
}
]
},
{
'name' : 'April 2015',
'info' : '5 Photos',
'media': [
{
'type' : 'photo',
'title' : 'Mountain Sunset',
'preview': 'assets/images/etc/mountain-sunset.jpg'
},
{
'type' : 'photo',
'title' : 'Mountain Lake',
'preview': 'assets/images/etc/mountain-lake.jpg'
},
{
'type' : 'photo',
'title' : 'Hot air balloons',
'preview': 'assets/images/etc/air-balloons.jpg'
},
{
'type' : 'photo',
'title' : 'Cactus',
'preview': 'assets/images/etc/cactus.jpg'
},
{
'type' : 'photo',
'title' : 'Road Trip',
'preview': 'assets/images/etc/road-trip.jpg'
},
{
'type' : 'photo',
'title' : 'Mountain Sunset',
'preview': 'assets/images/etc/mountain-sunset.jpg'
},
{
'type' : 'photo',
'title' : 'Mountain Lake',
'preview': 'assets/images/etc/mountain-lake.jpg'
}
]
}
];
public static about = {
'general': {
'gender' : 'Female',
'birthday' : 'May 8th, 1988',
'locations': [
'Istanbul, Turkey',
'New York, USA'
],
'about' : 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis eget pharetra felis, sed ullamcorper dui. Sed et elementum neque. Vestibulum pellente viverra ultrices. Etiam justo augue, vehicula ac gravida a, interdum sit amet nisl. Integer vitae nisi id nibh dictum mollis in vitae tortor.'
},
'work' : {
'occupation': 'Developer',
'skills' : 'C#, PHP, Javascript, Angular, JS, HTML, CSS',
'jobs' : [
{
'company': 'Self-Employed',
'date' : '2010 - Now'
},
{
'company': 'Google',
'date' : '2008 - 2010'
}
]
},
'contact': {
'address' : 'Ut pharetra luctus est quis sodales. Duis nisi tortor, bibendum eget tincidunt, aliquam ac elit. Mauris nec euismod odio.',
'tel' : [
'+6 555 6600',
'+9 555 5255'
],
'websites': [
'withinpixels.com'
],
'emails' : [
'mail@withinpixels.com',
'mail@creapond.com'
]
},
'groups' : [
{
'logo' : 'assets/images/logos/android.png',
'name' : 'Android',
'category': 'Technology',
'members' : '1.856.546'
},
{
'logo' : 'assets/images/logos/google.png',
'name' : 'Google',
'category': 'Web',
'members' : '1.226.121'
},
{
'logo' : 'assets/images/logos/fallout.png',
'name' : 'Fallout',
'category': 'Games',
'members' : '526.142'
}
],
'friends': [
{
'name' : 'Garry Newman',
'avatar': 'assets/images/avatars/garry.jpg'
},
{
'name' : 'Carl Henderson',
'avatar': 'assets/images/avatars/carl.jpg'
},
{
'name' : 'Jane Dean',
'avatar': 'assets/images/avatars/jane.jpg'
},
{
'name' : 'Garry Arnold',
'avatar': 'assets/images/avatars/garry.jpg'
},
{
'name' : 'Vincent Munoz',
'avatar': 'assets/images/avatars/vincent.jpg'
},
{
'name' : 'Alice Freeman',
'avatar': 'assets/images/avatars/alice.jpg'
},
{
'name' : 'Andrew Green',
'avatar': 'assets/images/avatars/andrew.jpg'
}
]
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
export class QuickPanelFakeDb
{
public static notes = [
{
'title' : 'Best songs to listen while working',
'detail': 'Last edit: May 8th, 2015'
},
{
'title' : 'Useful subreddits',
'detail': 'Last edit: January 12th, 2015'
}
];
public static events = [
{
'title' : 'Group Meeting',
'detail': 'In 32 Minutes, Room 1B'
},
{
'title' : 'Public Beta Release',
'detail': '11:00 PM'
},
{
'title' : 'Dinner with David',
'detail': '17:30 PM'
},
{
'title' : 'Q&A Session',
'detail': '20:30 PM'
}
];
}

View File

@@ -0,0 +1,787 @@
export class ScrumboardFakeDb
{
public static boards = [
{
'id' : '32gfhaf2',
'name' : 'ACME Frontend Application',
'uri' : 'acme-frontend-application',
'settings': {
'color' : 'fuse-dark',
'subscribed' : false,
'cardCoverImages': true
},
'lists' : [
{
'id' : '56027cf5a2ca3839a5d36103',
'name' : 'Design',
'idCards': [
'5603a2a3cab0c8300f6096b3',
'44d1.2b51ea6cc2b5d.21f4a3412e857.8ffa2d8b44ad9.ac87215ed53a1.67d4921ad8f8d.9f318bcb2'
]
},
{
'id' : '56127cf2a2ca3539g7d36103',
'name' : 'Development',
'idCards': [
'2837273da9b93dd84243s0f9',
'5787b7e4740c57bf0dffd5b6',
'5637273da9b93bb84743a0f9',
'7987.9740ba532b0d4.f9d12243f7362.507c0738dc561.87fba0a03df6e.75e6508cacf10.7a9835b54'
]
},
{
'id' : 'faf244627326f1249525763d',
'name' : 'Upcoming Features',
'idCards': [
'd9005a4b89ed2aadca48a6ad',
'f6b9d7a9247e5d794a081927',
'80ed.24ad3b18e2668.f28fbbceeeff9.5a834620a42f1.5909be19a2bf2.6c4a54947ce2d.da356b0c1',
'0ad2.7862f947bc456.f42b446df54cb.d1dd9e93601a1.9deb1406d1404.0b3c278fc7001.733341b42',
'bad3.51be8ad33acaf.9540ecb37f7e8.6bee596cfe7d3.44c68bee289c4.b96ed0b9f0af7.e14846035'
]
},
{
'id' : 'ad7d.9fffac5dff412.c83bca6853767.8fd7549b2b1ca.ceda8a01774c4.a5cf3976e87e4.ce79eeeea',
'name' : 'Known Bugs',
'idCards': [
'acc6.9c673cd2f5e35.521e91d8d5991.4b2a95e0539d1.027930c0743c5.7ad1ea7bea476.e8fbe6347',
'3279.3d69b40cc0b75.690252b6bea08.1e1789b0b7c2e.2f264b8661ce2.84d5f56910e23.429be5e8a',
'ba01.8e1a43f92a03a.0022bd5cbb9ba.275c64d911d8c.880e0846a3966.f75ff43e53ad.48ad612e7'
]
}
],
'cards' : [
{
'id' : '2837273da9b93dd84243s0f9',
'name' : 'Update generators',
'description' : 'Current generator doesn\'t support Node.js 6 and above.',
'idAttachmentCover': '',
'idMembers' : [
'26027s1930450d8bf7b10828'
],
'idLabels' : [
'26022e4129ad3a5sc28b36cd'
],
'attachments' : [],
'subscribed' : false,
'checklists' : [],
'checkItems' : 0,
'checkItemsChecked': 0,
'comments' : [
{
'idMember': '36027j1930450d8bf7b10158',
'message' : 'AngularCLI could be a nice alternative.',
'time' : 'now'
}
],
'activities' : [],
'due' : null
},
{
'id' : '5603a2a3cab0c8300f6096b3',
'name' : 'Change background colors',
'description' : '',
'idAttachmentCover': '67027cahbe3b52ecf2dc631c',
'idMembers' : [
'76027g1930450d8bf7b10958'
],
'idLabels' : [
'56027e4119ad3a5dc28b36cd',
'5640635e19ad3a5dc21416b2'
],
'attachments' : [
{
'id' : '67027cahbe3b52ecf2dc631c',
'name': 'mail.jpg',
'src' : 'assets/images/scrumboard/mail.jpg',
'time': 'Added Nov 3 at 15:22AM',
'type': 'image'
},
{
'id' : '56027cfcbe1b72ecf1fc452a',
'name': 'calendar.jpg',
'src' : 'assets/images/scrumboard/calendar.jpg',
'time': 'Added Nov 1 at 12:34PM',
'type': 'image'
}
],
'subscribed' : true,
'checklists' : [
{
'id' : '63021cfdbe1x72wcf1fc451v',
'name' : 'Checklist',
'checkItemsChecked': 1,
'checkItems' : [
{
'name' : 'Implement a calendar library',
'checked': false
},
{
'name' : 'Replace event colors with Material Design colors',
'checked': true
},
{
'name' : 'Replace icons with Material Design icons',
'checked': false
},
{
'name' : 'Use moment.js',
'checked': false
}
]
},
{
'name' : 'Checklist 2',
'id' : '74031cfdbe1x72wcz1dc166z',
'checkItemsChecked': 1,
'checkItems' : [
{
'name' : 'Replace event colors with Material Design colors',
'checked': true
},
{
'name' : 'Replace icons with Material Design icons',
'checked': false
},
{
'name' : 'Use moment.js',
'checked': false
}
]
}
],
'checkItems' : 7,
'checkItemsChecked': 2,
'comments' : [
{
'idMember': '56027c1930450d8bf7b10758',
'message' : 'We should be able to add moment.js without any problems',
'time' : '12 mins. ago'
},
{
'idMember': '36027j1930450d8bf7b10158',
'message' : 'I added a link for a page that might help us deciding the colors',
'time' : '30 mins. ago'
}
],
'activities' : [
{
'idMember': '56027c1930450d8bf7b10758',
'message' : 'added a comment',
'time' : '12 mins. ago'
},
{
'idMember': '36027j1930450d8bf7b10158',
'message' : 'added a comment',
'time' : '30 mins. ago'
},
{
'idMember': '36027j1930450d8bf7b10158',
'message' : 'attached a link',
'time' : '45 mins. ago'
}
],
'due' : 'Tue Aug 29 2017 13:16:34 GMT+0300 (Turkey Standard Time)'
},
{
'id' : '5637273da9b93bb84743a0f9',
'name' : 'Fix splash screen bugs',
'description' : '',
'idAttachmentCover': '',
'idMembers' : [
'56027c1930450d8bf7b10758'
],
'idLabels' : [
'5640635e19ad3a5dc21416b2'
],
'attachments' : [],
'subscribed' : true,
'checklists' : [],
'checkItems' : 0,
'checkItemsChecked': 0,
'comments' : [],
'activities' : [],
'due' : null
},
{
'id' : 'd9005a4b89ed2aadca48a6ad',
'name' : 'Add alternative authentication pages',
'description' : '',
'idAttachmentCover': '',
'idMembers' : [
'36027j1930450d8bf7b10158'
],
'idLabels' : [
'6540635g19ad3s5dc31412b2',
'56027e4119ad3a5dc28b36cd'
],
'attachments' : [],
'subscribed' : false,
'checklists' : [
{
'id' : 'dbfb.99bd0ad37dabc.e05046f0c824d.18f26bb524c96.78bebc8488634.240c0ee6a5e45.4cb872965',
'name' : 'Pages',
'checkItemsChecked': 2,
'checkItems' : [
{
'name' : 'Login',
'checked': true
},
{
'name' : 'Register',
'checked': true
},
{
'name' : 'Lost Password',
'checked': false
},
{
'name' : 'Recover Password',
'checked': false
},
{
'name' : 'Activate Account',
'checked': false
}
]
}
],
'checkItems' : 5,
'checkItemsChecked': 2,
'comments' : [],
'activities' : [],
'due' : null
},
{
'id' : '5787b7e4740c57bf0dffd5b6',
'name' : 'Fix the console',
'description' : 'We need to fix the console asap!',
'idAttachmentCover': '',
'idMembers' : [],
'idLabels' : [
'26022e4129ad3a5sc28b36cd'
],
'attachments' : [],
'subscribed' : true,
'checklists' : [],
'checkItems' : 0,
'checkItemsChecked': 0,
'comments' : [
{
'idMember': '36027j1930450d8bf7b10158',
'message' : 'I\'m on it!',
'time' : 'now'
}
],
'activities' : [],
'due' : 'Fri Sep 07 2018 15:00:00 GMT+0300 (Turkey Standard Time)'
},
{
'id' : 'f6b9d7a9247e5d794a081927',
'name' : 'New media player',
'description' : '',
'idAttachmentCover': '',
'idMembers' : [
'76027g1930450d8bf7b10958',
'56027c1930450d8bf7b10758',
'26027s1930450d8bf7b10828'
],
'idLabels' : [
'5640635e19ad3a5dc21416b2',
'6540635g19ad3s5dc31412b2'
],
'attachments' : [],
'subscribed' : false,
'checklists' : [],
'checkItems' : 0,
'checkItemsChecked': 0,
'comments' : [],
'activities' : [],
'due' : null
},
{
'id' : 'acc6.9c673cd2f5e35.521e91d8d5991.4b2a95e0539d1.027930c0743c5.7ad1ea7bea476.e8fbe6347',
'name' : 'Memory Leak',
'description' : '',
'idAttachmentCover': '',
'idMembers' : [
'36027j1930450d8bf7b10158'
],
'idLabels' : [
'26022e4129ad3a5sc28b36cd',
'5640635e19ad3a5dc21416b2'
],
'attachments' : [],
'subscribed' : false,
'checklists' : [],
'checkItems' : 0,
'checkItemsChecked': 0,
'comments' : [],
'activities' : [],
'due' : null
},
{
'id' : '3279.3d69b40cc0b75.690252b6bea08.1e1789b0b7c2e.2f264b8661ce2.84d5f56910e23.429be5e8a',
'name' : 'Broken toolbar on profile page',
'description' : '',
'idAttachmentCover': '',
'idMembers' : [
'26027s1930450d8bf7b10828'
],
'idLabels' : [
'26022e4129ad3a5sc28b36cd'
],
'attachments' : [],
'subscribed' : false,
'checklists' : [],
'checkItems' : 0,
'checkItemsChecked': 0,
'comments' : [
{
'idMember': '36027j1930450d8bf7b10158',
'message' : 'This should be a medium priority bug, shouldn\'t it?',
'time' : 'now'
}
],
'activities' : [],
'due' : null
},
{
'id' : 'ba01.8e1a43f92a03a.0022bd5cbb9ba.275c64d911d8c.880e0846a3966.f75ff43e53ad.48ad612e7',
'name' : 'Button hover style',
'description' : 'If there are 3 or more buttons in certain page, weird flashing happens when you hover over the red ones.',
'idAttachmentCover': '',
'idMembers' : [
'26027s1930450d8bf7b10828'
],
'idLabels' : [
'26022e4129ad3a5sc28b36cd',
'5640635e19ad3a5dc21416b2'
],
'attachments' : [],
'subscribed' : true,
'checklists' : [],
'checkItems' : 0,
'checkItemsChecked': 0,
'comments' : [],
'activities' : [],
'due' : 'Wed Mar 08 2017 12:00:00 GMT+0300 (Turkey Standard Time)'
},
{
'id' : '80ed.24ad3b18e2668.f28fbbceeeff9.5a834620a42f1.5909be19a2bf2.6c4a54947ce2d.da356b0c1',
'name' : 'New header designs',
'description' : '',
'idAttachmentCover': '12027cafbe3b52ecf2ef632c',
'idMembers' : [],
'idLabels' : [
'56027e4119ad3a5dc28b36cd',
'6540635g19ad3s5dc31412b2',
'5640635e19ad3a5dc21416b2'
],
'attachments' : [
{
'id' : '12027cafbe3b52ecf2ef632c',
'name': 'header-.jpg',
'src' : 'assets/images/scrumboard/header-1.jpg',
'time': 'Added Nov 3 at 15:22AM',
'type': 'image'
},
{
'id' : '55027ced1e1a12ecf1fced2a',
'name': 'header-2.jpg',
'src' : 'assets/images/scrumboard/header-2.jpg',
'time': 'Added Nov 1 at 12:34PM',
'type': 'image'
}
],
'subscribed' : false,
'checklists' : [],
'checkItems' : 0,
'checkItemsChecked': 0,
'comments' : [
{
'idMember': '36027j1930450d8bf7b10158',
'message' : 'Currently we have two new designs ready to ship.',
'time' : 'now'
}
],
'activities' : [],
'due' : null
},
{
'id' : '0ad2.7862f947bc456.f42b446df54cb.d1dd9e93601a1.9deb1406d1404.0b3c278fc7001.733341b42',
'name' : 'Fixed footer',
'description' : '',
'idAttachmentCover': '',
'idMembers' : [
'26027s1930450d8bf7b10828',
'56027c1930450d8bf7b10758'
],
'idLabels' : [
'6540635g19ad3s5dc31412b2'
],
'attachments' : [],
'subscribed' : true,
'checklists' : [],
'checkItems' : 0,
'checkItemsChecked': 0,
'comments' : [],
'activities' : [],
'due' : null
},
{
'id' : 'bad3.51be8ad33acaf.9540ecb37f7e8.6bee596cfe7d3.44c68bee289c4.b96ed0b9f0af7.e14846035',
'name' : 'Collapsable navigation',
'description' : '',
'idAttachmentCover': '',
'idMembers' : [],
'idLabels' : [
'6540635g19ad3s5dc31412b2'
],
'attachments' : [],
'subscribed' : false,
'checklists' : [],
'checkItems' : 0,
'checkItemsChecked': 0,
'comments' : [
{
'idMember': '36027j1930450d8bf7b10158',
'message' : 'I\'m not sure why we re-doing the navigation. The current collapsable navigation works flawlessly.',
'time' : 'now'
}
],
'activities' : [],
'due' : null
},
{
'id' : '44d1.2b51ea6cc2b5d.21f4a3412e857.8ffa2d8b44ad9.ac87215ed53a1.67d4921ad8f8d.9f318bcb2',
'name' : 'Mail app new layout',
'description' : 'Current layout has lots of flaws in mobile. Outlook view should help with that.',
'idAttachmentCover': '',
'idMembers' : [
'56027c1930450d8bf7b10758',
'26027s1930450d8bf7b10828',
'76027g1930450d8bf7b10958',
'36027j1930450d8bf7b10158'
],
'idLabels' : [
'56027e4119ad3a5dc28b36cd',
'26022e4129ad3a5sc28b36cd'
],
'attachments' : [],
'subscribed' : false,
'checklists' : [],
'checkItems' : 0,
'checkItemsChecked': 0,
'comments' : [],
'activities' : [],
'due' : null
},
{
'id' : '7987.9740ba532b0d4.f9d12243f7362.507c0738dc561.87fba0a03df6e.75e6508cacf10.7a9835b54',
'name' : 'API recover and monitoring',
'description' : 'We need a service to monitor and recover failed APIs.',
'idAttachmentCover': '',
'idMembers' : [
'36027j1930450d8bf7b10158',
'76027g1930450d8bf7b10958'
],
'idLabels' : [
'26022e4129ad3a5sc28b36cd',
'5640635e19ad3a5dc21416b2'
],
'attachments' : [],
'subscribed' : true,
'checklists' : [
{
'id' : '6926.2b31d119e4a.889401e0ca7a0.13ad8ce2e569d.976e54e8b5d87.456afccd7e820.d6c77106a',
'name' : 'API Monitoring',
'checkItemsChecked': 2,
'checkItems' : [
{
'name' : 'Simple dashboard design',
'checked': false
},
{
'name' : 'Should be able to see different time periods on the same dashboard',
'checked': true
},
{
'name' : 'Different colors for different clusters',
'checked': true
}
]
},
{
'id' : '7c22.5261c7924387f.248e8b1d32205.003f7a9f501d1.1d48dcdbe8b23.8099dcc5f75a7.29a966196',
'name' : 'API Recovery',
'checkItemsChecked': 1,
'checkItems' : [
{
'name' : 'Warning notifications to all developers',
'checked': false
},
{
'name' : 'Immediate recovery options attached to the notifications',
'checked': true
},
{
'name' : 'Backups every 6hours',
'checked': false
}
]
}
],
'checkItems' : 6,
'checkItemsChecked': 3,
'comments' : [],
'activities' : [],
'due' : 'Fri Feb 02 2017 14:20:34 GMT+0300 (Turkey Standard Time)'
}
],
'members' : [
{
'id' : '56027c1930450d8bf7b10758',
'name' : 'Alice Freeman',
'avatar': 'assets/images/avatars/alice.jpg'
},
{
'id' : '26027s1930450d8bf7b10828',
'name' : 'Danielle Obrien',
'avatar': 'assets/images/avatars/danielle.jpg'
},
{
'id' : '76027g1930450d8bf7b10958',
'name' : 'James Lewis',
'avatar': 'assets/images/avatars/james.jpg'
},
{
'id' : '36027j1930450d8bf7b10158',
'name' : 'Vincent Munoz',
'avatar': 'assets/images/avatars/vincent.jpg'
}
],
'labels' : [
{
'id' : '26022e4129ad3a5sc28b36cd',
'name' : 'High Priority',
'color': 'md-red-500-bg'
},
{
'id' : '56027e4119ad3a5dc28b36cd',
'name' : 'Design',
'color': 'md-orange-400-bg'
},
{
'id' : '5640635e19ad3a5dc21416b2',
'name' : 'App',
'color': 'md-blue-600-bg'
},
{
'id' : '6540635g19ad3s5dc31412b2',
'name' : 'Feature',
'color': 'md-green-400-bg'
}
]
},
{
'id' : '27cfcbe1',
'name' : 'ACME Backend Application',
'uri' : 'acme-backend-application',
'settings': {
'color' : 'blue-grey',
'subscribed' : false,
'cardCoverImages': true
},
'lists' : [
{
'id' : '56027cf5a2ca3839a5d36103',
'name' : 'Designs',
'idCards': [
'5603a2a3cab0c8300f6096b3'
]
},
{
'id' : '56127cf2a2ca3539g7d36103',
'name' : 'Development',
'idCards': [
'5637273da9b93bb84743a0f9'
]
}
],
'cards' : [
{
'id' : '5603a2a3cab0c8300f6096b3',
'name' : 'Calendar App Design',
'description' : '',
'idAttachmentCover': '56027cfcbe1b72ecf1fc452a',
'idMembers' : [
'56027c1930450d8bf7b10758',
'36027j1930450d8bf7b10158'
],
'idLabels' : [
'56027e4119ad3a5dc28b36cd',
'5640635e19ad3a5dc21416b2'
],
'attachments' : [
{
'id' : '56027cfcbe1b72ecf1fc452a',
'name': 'calendar-app-design.jpg',
'src' : 'assets/images/scrumboard/calendar.jpg',
'time': 'Added Nov 1 at 12:34PM',
'type': 'image'
},
{
'id' : '67027cahbe3b52ecf2dc631c',
'url' : 'assets/images/scrumboard/calendar.jpg',
'time': 'Added Nov 3 at 15:22AM',
'type': 'link'
}
],
'subscribed' : true,
'checklists' : [
{
'id' : '63021cfdbe1x72wcf1fc451v',
'name' : 'Checklist',
'checkItemsChecked': 1,
'checkItems' : [
{
'name' : 'Implement a calendar library',
'checked': false
},
{
'name' : 'Replace event colors with Material Design colors',
'checked': true
},
{
'name' : 'Replace icons with Material Design icons',
'checked': false
},
{
'name' : 'Use moment.js',
'checked': false
}
]
},
{
'name' : 'Checklist 2',
'id' : '74031cfdbe1x72wcz1dc166z',
'checkItemsChecked': 1,
'checkItems' : [
{
'name' : 'Replace event colors with Material Design colors',
'checked': true
},
{
'name' : 'Replace icons with Material Design icons',
'checked': false
},
{
'name' : 'Use moment.js',
'checked': false
}
]
}
],
'checkItems' : 7,
'checkItemsChecked': 2,
'comments' : [
{
'idMember': '56027c1930450d8bf7b10758',
'message' : 'We should be able to add moment.js without any problems',
'time' : '12 mins. ago'
},
{
'idMember': '36027j1930450d8bf7b10158',
'message' : 'I added a link for a page that might help us deciding the colors',
'time' : '30 mins. ago'
}
],
'activities' : [
{
'idMember': '56027c1930450d8bf7b10758',
'message' : 'added a comment',
'time' : '12 mins. ago'
},
{
'idMember': '36027j1930450d8bf7b10158',
'message' : 'added a comment',
'time' : '30 mins. ago'
},
{
'idMember': '36027j1930450d8bf7b10158',
'message' : 'attached a link',
'time' : '45 mins. ago'
}
],
'due' : null
},
{
'id' : '5637273da9b93bb84743a0f9',
'name' : 'Fix Splash Screen bugs',
'description' : '',
'idAttachmentCover': '5603a2ae2bbd55bb2db57478',
'idMembers' : [
'56027c1930450d8bf7b10758'
],
'idLabels' : [],
'attachments' : [
{
'id' : '5603a2ae2bbd55bb2db57478',
'name': 'mail-app-design.jpg',
'src' : 'assets/images/scrumboard/mail.jpg',
'time': 'Added Nov 1 at 12:34PM',
'type': 'image'
}
],
'subscribed' : true,
'checklists' : [],
'checkItems' : 0,
'checkItemsChecked': 0,
'comments' : [],
'activities' : [],
'due' : null
}
],
'members' : [
{
'id' : '56027c1930450d8bf7b10758',
'name' : 'Alice Freeman',
'avatar': 'assets/images/avatars/alice.jpg'
},
{
'id' : '26027s1930450d8bf7b10828',
'name' : 'Danielle Obrien',
'avatar': 'assets/images/avatars/danielle.jpg'
},
{
'id' : '76027g1930450d8bf7b10958',
'name' : 'James Lewis',
'avatar': 'assets/images/avatars/james.jpg'
},
{
'id' : '36027j1930450d8bf7b10158',
'name' : 'Vincent Munoz',
'avatar': 'assets/images/avatars/vincent.jpg'
}
],
'labels' : [
{
'id' : '56027e4119ad3a5dc28b36cd',
'name' : 'Design',
'color': 'md-red-500-bg'
},
{
'id' : '5640635e19ad3a5dc21416b2',
'name' : 'App',
'color': 'md-blue-500-bg'
},
{
'id' : '6540635g19ad3s5dc31412b2',
'name' : 'Feature',
'color': 'md-green-400-bg'
}
]
}
];
}

View File

@@ -0,0 +1,139 @@
export class SearchFakeDb
{
public static classic = [
{
'title' : 'Dynamically Procrastinate B2C',
'url' : 'ourwebaddress.com/articles/procrastinate',
'excerpt': 'Collaboratively administrate empowered markets via plug-and-play networks. Dynamically procrastinate B2C users after installed base benefits.'
},
{
'title' : 'Cross Media',
'url' : 'ourwebaddress.com/articles/cross-media',
'excerpt': 'Efficiently unleash cross-media information without cross-media value. Quickly maximize timely deliverables for real-time schemas.'
},
{
'title' : 'Synergize',
'url' : 'ourwebaddress.com/articles/synergize',
'excerpt': 'Completely synergize resource taxing relationships via premier niche markets. Professionally cultivate one-to-one customer service with robust ideas.'
},
{
'title' : 'Parallel Platforms',
'url' : 'ourwebaddress.com/articles/parallel-paltforms',
'excerpt': 'Objectively innovate empowered manufactured products whereas parallel platforms. Holisticly predominate extensible testing procedures for reliable supply chains.'
},
{
'title' : 'Growth Strategies',
'url' : 'ourwebaddress.com/articles/growth-strategies',
'excerpt': 'Proactively envisioned multimedia based expertise and cross-media growth strategies. Holistically pontificate installed base portals after maintainable products.'
},
{
'title' : 'Methodologies',
'url' : 'ourwebaddress.com/articles/methodologies',
'excerpt': 'Phosfluorescently engage worldwide methodologies with web-enabled technology. Completely pursue scalable customer service through sustainable potentialities.'
},
{
'title' : 'E-tailers',
'url' : 'ourwebaddress.com/articles/e-trailers',
'excerpt': 'Collaboratively administrate turnkey channels whereas virtual e-tailers. Objectively seize scalable metrics whereas proactive e-services.'
},
{
'title' : 'Web Readiness',
'url' : 'ourwebaddress.com/articles/web-readiness',
'excerpt': 'Credibly innovate granular internal or organic sources whereas high standards in web-readiness. Dramatically synthesize integrated schemas with optimal networks.'
}
];
public static table = [
{
'name' : 'Airi Satou',
'position' : 'Accountant',
'office' : 'Tokyo',
'age' : '33',
'startDate': '2008/11/28',
'salary' : '162700',
'email' : 'a.satou@mail.com'
},
{
'name' : 'Angellica Ramos',
'position' : 'Chief Executive Officer (CEO)',
'office' : 'London',
'age' : '47',
'startDate': '2009/10/09',
'salary' : '1200000',
'email' : 'a.ramos@mail.com'
},
{
'name' : 'Ashton Cox',
'position' : 'Hunior Technical Author',
'office' : 'San Fransisco',
'age' : '66',
'startDate': '2009/01/12',
'salary' : '86000',
'email' : 'a.cox@mail.com'
},
{
'name' : 'Bradley Greer',
'position' : 'Software Engineer',
'office' : 'London',
'age' : '41',
'startDate': '2012/10/13',
'salary' : '132000',
'email' : 'b.greer@mail.com'
},
{
'name' : 'Brenden Wagner',
'position' : 'Software Engineer',
'office' : 'San Fransisco',
'age' : '28',
'startDate': '2011/06/07',
'salary' : '206850',
'email' : 'b.wagner@mail.com'
},
{
'name' : 'Brielle Williamson',
'position' : 'Integration Specialist',
'office' : 'New York',
'age' : '61',
'startDate': '2012/12/02',
'salary' : '372000',
'email' : 'b.williamson@mail.com'
},
{
'name' : 'Bruno Nash',
'position' : 'Software Engineer',
'office' : 'London',
'age' : '38',
'startDate': '2011/05/03',
'salary' : '163500',
'email' : 'b.nash@mail.com'
},
{
'name' : 'Caesar Vance',
'position' : 'Pre-Sales Support',
'office' : 'New York',
'age' : '21',
'startDate': '2011/12/12',
'salary' : '106450',
'email' : 'c.vance@mail.com'
},
{
'name' : 'Cara Stevens',
'position' : 'Sales Assistant',
'office' : 'New York',
'age' : '46',
'startDate': '2011/12/06',
'salary' : '145600',
'email' : 'c.stevens@mail.com'
},
{
'name' : 'Cedric Kelly',
'position' : 'Senior Javascript Developer',
'office' : 'Edinburg',
'age' : '22',
'startDate': '2012/03/29',
'salary' : '433060',
'email' : 'c.kelly@mail.com'
}
];
}

View File

@@ -0,0 +1,324 @@
export class TodoFakeDb
{
public static todos = [
{
'id' : '561551bd7fe2ff461101c192',
'title' : 'Proident tempor est nulla irure ad est',
'notes' : 'Id nulla nulla proident deserunt deserunt proident in quis. Cillum reprehenderit labore id anim laborum.',
'startDate': 'Wednesday, January 29, 2014 3:17 PM',
'dueDate' : null,
'completed': false,
'starred' : false,
'important': false,
'deleted' : false,
'tags' : [1]
},
{
'id' : '561551bd4ac1e7eb77a3a750',
'title' : 'Magna quis irure quis ea pariatur laborum',
'notes' : '',
'startDate': 'Sunday, February 1, 2015 1:30 PM',
'dueDate' : 'Friday, December 30, 2016 10:07 AM',
'completed': false,
'starred' : false,
'important': true,
'deleted' : false,
'tags' : [1, 4]
},
{
'id' : '561551bd917bfec2ddef2d49',
'title' : 'Ullamco duis commodo sint ad aliqua aute',
'notes' : 'Sunt laborum enim nostrud ea fugiat cillum mollit aliqua exercitation ad elit.',
'startDate': 'Friday, April 11, 2014 3:43 AM',
'dueDate' : 'Wednesday, July 26, 2017 11:14 AM',
'completed': false,
'starred' : true,
'important': true,
'deleted' : false,
'tags' : [3]
},
{
'id' : '561551bdeeb2fd6877e18c29',
'title' : 'Eiusmod non occaecat pariatur Lorem in ex',
'notes' : 'Nostrud anim mollit incididunt qui qui sit commodo duis. Anim amet irure aliquip duis nostrud sit quis fugiat ullamco non dolor labore. Lorem sunt voluptate laboris culpa proident. Aute eiusmod aliqua exercitation irure exercitation qui laboris mollit occaecat eu occaecat fugiat.',
'startDate': 'Wednesday, May 7, 2014 4:14 AM',
'dueDate' : 'Friday, December 15, 2017 4:01 AM',
'completed': true,
'starred' : true,
'important': false,
'deleted' : false,
'tags' : [2]
},
{
'id' : '561551bdf38eae0134ae43d4',
'title' : 'Lorem magna cillum consequat consequat mollit',
'notes' : 'Velit ipsum proident ea incididunt et. Consectetur eiusmod laborum voluptate duis occaecat ullamco sint enim proident.',
'startDate': 'Sunday, August 23, 2015 11:19 PM',
'dueDate' : 'Friday, July 8, 2016 10:49 AM',
'completed': false,
'starred' : false,
'important': false,
'deleted' : false,
'tags' : [5, 4]
},
{
'id' : '561551bd32f1588c814a0ccd',
'title' : 'Quis irure cupidatat ad consequat reprehenderit excepteur',
'notes' : 'Esse nisi mollit aliquip mollit aute consequat adipisicing. Do excepteur dolore proident cupidatat pariatur irure consequat incididunt.',
'startDate': 'Sunday, June 7, 2015 10:49 AM',
'dueDate' : 'Monday, January 9, 2017 8:34 AM',
'completed': false,
'starred' : true,
'important': false,
'deleted' : false,
'tags' : [2, 3]
},
{
'id' : '561551bd0bb4b08ca77038ef',
'title' : 'Officia voluptate tempor ut mollit ea cillum',
'notes' : 'Deserunt veniam reprehenderit do elit magna ut.',
'startDate': 'Saturday, October 18, 2014 4:25 AM',
'dueDate' : 'Sunday, August 21, 2016 10:48 PM',
'completed': true,
'starred' : false,
'important': false,
'deleted' : false,
'tags' : [2, 4]
},
{
'id' : '561551bdf84eec913835ebe5',
'title' : 'Sit exercitation cupidatat minim est ipsum excepteur',
'notes' : '',
'startDate': 'Friday, August 8, 2014 5:45 AM',
'dueDate' : 'Wednesday, June 15, 2016 1:53 PM',
'completed': true,
'starred' : false,
'important': true,
'deleted' : false,
'tags' : [1, 3]
},
{
'id' : '561551bd2047cc709af0f670',
'title' : 'Sunt fugiat officia nisi minim sunt duis',
'notes' : 'Eiusmod eiusmod sint aliquip exercitation cillum. Magna nulla officia ex consectetur ea ad excepteur in qui.',
'startDate': 'Monday, July 13, 2015 1:55 PM',
'dueDate' : 'Thursday, March 3, 2016 2:26 PM',
'completed': false,
'starred' : false,
'important': false,
'deleted' : false,
'tags' : [
{
'id' : 5,
'name' : 'mobile',
'label': 'Mobile',
'color': '#9C27B0'
}
]
},
{
'id' : '561551bd73d1a627e97005ce',
'title' : 'Non cupidatat enim quis aliquip minim laborum',
'notes' : 'Qui cillum eiusmod nostrud sunt dolore velit nostrud labore voluptate ad dolore. Eu Lorem anim pariatur aliqua. Ullamco ut dolor velit esse occaecat dolore eu cillum commodo qui. Nulla dolor consequat voluptate magna ut commodo magna consectetur non aute proident.',
'startDate': 'Tuesday, November 11, 2014 6:36 PM',
'dueDate' : 'Tuesday, August 9, 2016 7:18 AM',
'completed': false,
'starred' : false,
'important': false,
'deleted' : false,
'tags' : [2]
},
{
'id' : '561551bd8f7d793ded0a2353',
'title' : 'Dolor ex occaecat magna labore laboris qui',
'notes' : 'Incididunt qui excepteur eiusmod elit cillum occaecat voluptate cillum nostrud. Dolor ullamco ullamco eiusmod do sunt adipisicing pariatur. In esse esse labore id reprehenderit sint do. Pariatur culpa dolor tempor qui excepteur duis do anim minim ipsum.',
'startDate': 'Monday, June 9, 2014 3:15 PM',
'dueDate' : 'Wednesday, October 19, 2016 3:38 PM',
'completed': false,
'starred' : false,
'important': true,
'deleted' : false,
'tags' : [3]
},
{
'id' : '561551bdaa586f72d0be02cc',
'title' : 'Ex nisi amet id dolore nostrud esse',
'notes' : '',
'startDate': 'Thursday, January 15, 2015 6:11 PM',
'dueDate' : 'Sunday, August 20, 2017 10:02 AM',
'completed': false,
'starred' : true,
'important': true,
'deleted' : false,
'tags' : [4]
},
{
'id' : '561551bd9f1c2de5b27f537b',
'title' : 'In dolor velit labore dolore ex eiusmod',
'notes' : '',
'startDate': 'Monday, March 10, 2014 12:50 AM',
'dueDate' : 'Thursday, January 26, 2017 3:10 PM',
'completed': false,
'starred' : false,
'important': false,
'deleted' : false,
'tags' : [4]
},
{
'id' : '561551bd26e21bb5e85b35cb',
'title' : 'Sunt voluptate aliquip exercitation minim magna sit',
'notes' : '',
'startDate': 'Tuesday, March 24, 2015 10:54 PM',
'dueDate' : 'Wednesday, August 23, 2017 5:35 PM',
'completed': false,
'starred' : false,
'important': false,
'deleted' : false,
'tags' : [4]
},
{
'id' : '561551bd719860cf0ad2011a',
'title' : 'Nisi et ullamco minim ea proident tempor',
'notes' : 'Dolor veniam dolor cillum Lorem magna nisi in occaecat nulla dolor ea eiusmod.',
'startDate': 'Friday, February 14, 2014 10:03 AM',
'dueDate' : 'Saturday, July 8, 2017 11:54 PM',
'completed': false,
'starred' : true,
'important': false,
'deleted' : false,
'tags' : [2, 4]
},
{
'id' : '561551bd49d800c243264a91',
'title' : 'Sit ipsum mollit cupidatat adipisicing officia aliquip',
'notes' : '',
'startDate': 'Wednesday, December 10, 2014 9:25 AM',
'dueDate' : 'Friday, March 25, 2016 12:29 AM',
'completed': true,
'starred' : false,
'important': false,
'deleted' : false,
'tags' : [1]
},
{
'id' : '561551bd061990eaf40fb64f',
'title' : 'Amet sunt et quis amet commodo quis',
'notes' : 'Nulla dolore consequat aliqua sint consequat elit qui occaecat et.',
'startDate': 'Saturday, March 1, 2014 3:59 PM',
'dueDate' : 'Saturday, November 7, 2015 2:00 PM',
'completed': false,
'starred' : false,
'important': true,
'deleted' : false,
'tags' : [1]
},
{
'id' : '561551be81d05fa94711e7f3',
'title' : 'Ut eiusmod ex ea eiusmod culpa incididunt',
'notes' : 'Fugiat non incididunt officia ex incididunt occaecat. Voluptate nostrud culpa aliquip mollit incididunt non dolore.',
'startDate': 'Monday, February 2, 2015 3:07 PM',
'dueDate' : 'Saturday, October 14, 2017 6:57 AM',
'completed': false,
'starred' : false,
'important': false,
'deleted' : false,
'tags' : [2]
},
{
'id' : '561551be05c093a80e0c8d05',
'title' : 'Proident reprehenderit laboris pariatur ut et nisi',
'notes' : 'Reprehenderit proident ut ad cillum quis velit quis aliqua ut aliquip tempor ullamco.',
'startDate': 'Sunday, June 14, 2015 4:40 AM',
'dueDate' : 'Wednesday, February 10, 2016 10:47 AM',
'completed': true,
'starred' : true,
'important': true,
'deleted' : false,
'tags' : [5]
},
{
'id' : '561551be3bb43a5bd431c2fc',
'title' : 'Aliqua aliquip aliquip aliquip et exercitation aute',
'notes' : 'Adipisicing Lorem tempor ex anim. Labore tempor laboris nostrud dolore voluptate ullamco. Fugiat ex deserunt anim minim esse velit laboris aute ea duis incididunt. Elit irure id Lorem incididunt laborum aliquip consectetur est irure sunt. Ut labore anim nisi aliqua tempor laborum nulla cillum. Duis irure consequat cillum magna cillum eiusmod ut. Et exercitation voluptate quis deserunt elit quis dolor deserunt ex ex esse ex.',
'startDate': 'Saturday, May 3, 2014 1:32 AM',
'dueDate' : 'Monday, September 12, 2016 9:16 PM',
'completed': true,
'starred' : false,
'important': true,
'deleted' : true,
'tags' : [3]
}
];
public static filters = [
{
'id' : 0,
'handle': 'starred',
'title' : 'Starred',
'icon' : 'star'
},
{
'id' : 1,
'handle': 'important',
'title' : 'Priority',
'icon' : 'error'
},
{
'id' : 2,
'handle': 'dueDate',
'title' : 'Sheduled',
'icon' : 'schedule'
},
{
'id' : 3,
'handle': 'today',
'title' : 'Today',
'icon' : 'today'
},
{
'id' : 4,
'handle': 'completed',
'title' : 'Done',
'icon' : 'check'
},
{
'id' : 4,
'handle': 'deleted',
'title' : 'Deleted',
'icon' : 'delete'
}
];
public static tags = [
{
'id' : 1,
'handle': 'frontend',
'title' : 'Frontend',
'color' : '#388E3C'
},
{
'id' : 2,
'handle': 'backend',
'title' : 'Backend',
'color' : '#F44336'
},
{
'id' : 3,
'handle': 'api',
'title' : 'API',
'color' : '#FF9800'
},
{
'id' : 4,
'handle': 'issue',
'title' : 'Issue',
'color' : '#0091EA'
},
{
'id' : 5,
'handle': 'mobile',
'title' : 'Mobile',
'color' : '#9C27B0'
}
];
}

View File

@@ -0,0 +1,127 @@
<div id="calendar" class="page-layout simple fullwidth" fusePerfectScrollbar>
<!-- HEADER -->
<div class="header p-16 p-sm-24" [ngClass]="viewDate | date:'MMM'">
<div class="header-content" fxLayout="column" fxLayoutAlign="space-between">
<div class="header-top" fxLayout="row" fxLayoutAlign="space-between center" fxLayout.xs="column">
<div class="logo mb-16 mb-sm-0" fxLayout="row" fxLayoutAlign="start center">
<md-icon class="logo-icon" *fuseIfOnDom [@animate]="{value:'*',params:{delay:'50ms',scale:'0.2'}}">today</md-icon>
<span class="logo-text" *fuseIfOnDom [@animate]="{value:'*',params:{delay:'100ms',x:'-25px'}}">Calendar</span>
</div>
<!-- TOOLBAR -->
<div class="toolbar" fxLayout="row" fxLayoutAlign="start center">
<button md-button class="mat-icon-button" aria-label="Search" md-tooltip="Search">
<md-icon>search</md-icon>
</button>
<button md-button class="mat-icon-button"
mwlCalendarToday
[(viewDate)]="viewDate"
(viewDateChange)="selectedDay = {date:$event}"
aria-label="Today" md-tooltip="Today">
<!--(click)="selectedDay = viewDate"-->
<md-icon>today</md-icon>
</button>
<button md-button class="mat-icon-button" (click)="view='day'"
aria-label="Day" md-tooltip="Day">
<md-icon>view_day</md-icon>
</button>
<button md-button class="mat-icon-button" (click)="view='week'"
aria-label="Week" md-tooltip="Week">
<md-icon>view_week</md-icon>
</button>
<button md-button class="mat-icon-button" (click)="view='month'"
aria-label="Month" md-tooltip="Month">
<md-icon>view_module</md-icon>
</button>
</div>
</div>
<!-- / TOOLBAR -->
<!-- HEADER BOTTOM -->
<div class="header-bottom" fxLayout="row" fxLayoutAlign="center center"
*fuseIfOnDom [@animate]="{value:'*',params:{delay:'150ms'}}">
<button md-button class="mat-icon-button arrow"
mwlCalendarPreviousView
[view]="view"
[(viewDate)]="viewDate"
(viewDateChange)="selectedDay = {date:$event}"
aria-label="Previous">
<md-icon>chevron_left</md-icon>
</button>
<div class="title">
{{ viewDate | calendarDate:(view + 'ViewTitle'):'en' }}
</div>
<button md-button class="mat-icon-button arrow"
mwlCalendarNextView
[view]="view"
[(viewDate)]="viewDate"
(viewDateChange)="selectedDay = {date:$event}"
aria-label="Next">
<md-icon>chevron_right</md-icon>
</button>
</div>
<!-- / HEADER BOTTOM -->
</div>
<!-- ADD EVENT BUTTON -->
<button md-fab class="add-event-button mat-warn" (click)="addEvent()" aria-label="Add event"
*fuseIfOnDom [@animate]="{value:'*',params:{delay:'300ms',scale:'0.2'}}">
<md-icon>add</md-icon>
</button>
<!-- / ADD EVENT BUTTON -->
</div>
<!-- / HEADER -->
<!-- CONTENT -->
<div class="content" fusePerfectScrollbar *fuseIfOnDom [@animate]="{value:'*',params:{delay:'200ms',y:'50px'}}">
<div [ngSwitch]="view">
<mwl-calendar-month-view
*ngSwitchCase="'month'"
[viewDate]="viewDate"
[events]="events"
[refresh]="refresh"
[activeDayIsOpen]="activeDayIsOpen"
(dayClicked)="dayClicked($event.day)"
(eventClicked)="editEvent('edit', $event.event)"
(eventTimesChanged)="eventTimesChanged($event)"
(beforeViewRender)="beforeMonthViewRender($event)">
</mwl-calendar-month-view>
<mwl-calendar-week-view
*ngSwitchCase="'week'"
[viewDate]="viewDate"
(viewDateChange)="selectedDay = {date:$event}"
[events]="events"
[refresh]="refresh"
(dayClicked)="dayClicked($event.day)"
(eventClicked)="editEvent('edit', $event.event)"
(eventTimesChanged)="eventTimesChanged($event)">
</mwl-calendar-week-view>
<mwl-calendar-day-view
*ngSwitchCase="'day'"
[viewDate]="viewDate"
(viewDateChange)="selectedDay = {date:$event}"
[events]="events"
[refresh]="refresh"
(dayClicked)="dayClicked($event.day)"
(eventClicked)="editEvent('edit', $event.event)"
(eventTimesChanged)="eventTimesChanged($event)">
</mwl-calendar-day-view>
</div>
</div>
<!-- / CONTENT -->
</div>

View File

@@ -0,0 +1,314 @@
@import "src/app/core/scss/fuse";
@import "node_modules/angular-calendar/scss/angular-calendar";
.cal-month-view {
.cal-header {
.cal-cell {
font-weight: 500;
}
}
.cal-day-cell {
@include media-breakpoint(lg) {
min-height: 150px;
}
@include media-breakpoint(gt-lg) {
min-height: 200px;
}
&.cal-open {
@include mat-elevation(3);
}
}
.cal-open-day-events {
background: #455A64;
box-shadow: inset 0 0 12px 0 rgba(0, 0, 0, 0.54);
padding: 0;
display: flex;
flex-direction: column;
> div {
padding: 0 16px;
margin: 8px 16px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: start;
background-color: white;
@include mat-elevation(1);
transition: box-shadow 300ms ease;
&:first-of-type {
margin-top: 16px;
}
&:last-of-type {
margin-bottom: 16px;
}
&:hover {
@include mat-elevation(3);
}
.cal-event {
top: 0;
margin: 0;
}
mwl-calendar-event-title {
flex: 1;
.cal-event-title {
display: block;
padding: 21px 24px;
line-height: 1;
text-decoration: none;
color: black;
}
}
mwl-calendar-event-actions {
.cal-event-actions {
display: flex;
flex-direction: row;
align-items: center;
.cal-event-action {
display: block;
line-height: 1;
padding: 8px;
}
}
}
}
}
}
.cal-week-view {
.cal-header > b {
font-weight: 500;
}
.cal-event {
display: flex;
flex-direction: row;
align-items: center;
mwl-calendar-event-title {
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1;
order: 0;
.cal-event-title {
display: block;
//padding: 21px 24px;
line-height: 1;
text-decoration: none;
color: black;
}
}
mwl-calendar-event-actions {
order: 1;
.cal-event-actions {
display: flex;
flex-direction: row;
align-items: center;
.cal-event-action {
display: block;
line-height: 1;
padding: 8px;
}
}
}
}
}
.cal-day-view {
.cal-time {
font-weight: 500;
}
.cal-event {
display: flex;
flex-direction: row;
mwl-calendar-event-title {
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1;
order: 0;
.cal-event-title {
display: block;
height: 26px;
line-height: 26px;
text-decoration: none;
color: black;
}
}
mwl-calendar-event-actions {
order: 1;
.cal-event-actions {
display: flex;
flex-direction: row;
align-items: center;
.cal-event-action {
display: block;
line-height: 1;
padding: 4px;
}
}
}
}
}
#calendar {
background: #FFFFFF;
overflow-x: hidden;
overflow-y: auto;
.header {
height: 200px;
min-height: 200px;
max-height: 200px;
position: relative;
background-size: 100% auto;
background-position: 0 50%;
background-repeat: no-repeat;
background-color: #FAFAFA;
color: #FFFFFF;
@include media-breakpoint(xs) {
height: 164px;
min-height: 164px;
max-height: 164px;
}
&:before {
content: '';
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1;
background: rgba(0, 0, 0, 0.45);
}
&.Jan {
background-image: url('/assets/images/backgrounds/january.jpg');
background-position: 0 45%;
}
&.Feb {
background-image: url('/assets/images/backgrounds/february.jpg');
background-position: 0 50%;
}
&.Mar {
background-image: url('/assets/images/backgrounds/march.jpg');
background-position: 0 45%;
}
&.Apr {
background-image: url('/assets/images/backgrounds/april.jpg');
background-position: 0 48%;
}
&.May {
background-image: url('/assets/images/backgrounds/may.jpg');
background-position: 0 47%;
}
&.Jun {
background-image: url('/assets/images/backgrounds/june.jpg');
background-position: 0 48%;
}
&.Jul {
background-image: url('/assets/images/backgrounds/july.jpg');
background-position: 0 3%;
}
&.Aug {
background-image: url('/assets/images/backgrounds/august.jpg');
background-position: 0 61%;
}
&.Sep {
background-image: url('/assets/images/backgrounds/september.jpg');
background-position: 0 58%;
}
&.Oct {
background-image: url('/assets/images/backgrounds/october.jpg');
background-position: 0 50%;
}
&.Nov {
background-image: url('/assets/images/backgrounds/november.jpg');
background-position: 0 46%;
}
&.Dec {
background-image: url('/assets/images/backgrounds/december.jpg');
background-position: 0 43%;
}
.header-content {
height: 100%;
.header-top {
position: relative;
z-index: 2;
.logo {
.logo-icon {
margin-right: 16px;
}
.logo-text {
font-size: 24px;
}
}
}
.header-bottom {
position: relative;
z-index: 2;
.title {
font-size: 20px;
min-width: 160px;
text-align: center;
font-weight: 500;
}
}
}
.add-event-button {
position: absolute;
right: 18px;
bottom: -32px;
z-index: 10;
}
md-icon {
color: #FFFFFF;
}
}
.content {
padding: 24px;
}
}

View File

@@ -0,0 +1,268 @@
import { startOfDay, endOfDay, subDays, addDays, endOfMonth, isSameDay, isSameMonth, addHours } from 'date-fns';
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { Subject } from 'rxjs/Subject';
import { MdDialog, MdDialogRef } from '@angular/material';
import { FuseCalendarEventFormDialogComponent } from './event-form/event-form.component';
import { FormGroup } from '@angular/forms';
import { CalendarEventModel } from './event.model';
import { CalendarService } from './calendar.service';
import {
CalendarEvent,
CalendarEventAction,
CalendarEventTimesChangedEvent,
CalendarMonthViewDay
} from 'angular-calendar';
import { FuseConfirmDialogComponent } from '../../../../core/components/confirm-dialog/confirm-dialog.component';
import { fuseAnimations } from '../../../../core/animations';
@Component({
selector : 'fuse-calendar',
templateUrl : './calendar.component.html',
styleUrls : ['./calendar.component.scss'],
encapsulation: ViewEncapsulation.None,
animations : fuseAnimations
})
export class FuseCalendarComponent implements OnInit
{
view: string;
viewDate: Date;
events: CalendarEvent[];
public actions: CalendarEventAction[];
activeDayIsOpen: boolean;
refresh: Subject<any> = new Subject();
dialogRef: any;
confirmDialogRef: MdDialogRef<FuseConfirmDialogComponent>;
selectedDay: any;
constructor(
public dialog: MdDialog,
public calendarService: CalendarService
)
{
this.view = 'month';
this.viewDate = new Date();
this.activeDayIsOpen = true;
this.selectedDay = {date: startOfDay(new Date())};
this.actions = [
{
label : '<i class="material-icons s-16">edit</i>',
onClick: ({event}: { event: CalendarEvent }): void => {
this.editEvent('edit', event);
}
},
{
label : '<i class="material-icons s-16">delete</i>',
onClick: ({event}: { event: CalendarEvent }): void => {
this.deleteEvent(event);
}
}
];
/**
* Get events from service/server
*/
this.setEvents();
}
ngOnInit()
{
/**
* Watch re-render-refresh for updating db
*/
this.refresh.subscribe(updateDB => {
// console.warn('REFRESH');
if ( updateDB )
{
// console.warn('UPDATE DB');
this.calendarService.updateEvents(this.events);
}
});
this.calendarService.onEventsUpdated.subscribe(events => {
this.setEvents();
this.refresh.next();
});
}
setEvents()
{
this.events = this.calendarService.events.map(item => {
item.actions = this.actions;
return new CalendarEventModel(item);
});
}
/**
* Before View Renderer
* @param {any} header
* @param {any} body
*/
beforeMonthViewRender({header, body})
{
// console.info('beforeMonthViewRender');
/**
* Get the selected day
*/
const _selectedDay = body.find((_day) => {
return _day.date.getTime() === this.selectedDay.date.getTime();
});
if ( _selectedDay )
{
/**
* Set selectedday style
* @type {string}
*/
_selectedDay.cssClass = 'mat-elevation-z3';
}
}
/**
* Day clicked
* @param {MonthViewDay} day
*/
dayClicked(day: CalendarMonthViewDay): void
{
const date: Date = day.date;
const events: CalendarEvent[] = day.events;
if ( isSameMonth(date, this.viewDate) )
{
if ( (isSameDay(this.viewDate, date) && this.activeDayIsOpen === true) || events.length === 0 )
{
this.activeDayIsOpen = false;
}
else
{
this.activeDayIsOpen = true;
this.viewDate = date;
}
}
this.selectedDay = day;
this.refresh.next();
}
/**
* Event times changed
* Event dropped or resized
* @param {CalendarEvent} event
* @param {Date} newStart
* @param {Date} newEnd
*/
eventTimesChanged({event, newStart, newEnd}: CalendarEventTimesChangedEvent): void
{
event.start = newStart;
event.end = newEnd;
// console.warn('Dropped or resized', event);
this.refresh.next(true);
}
/**
* Delete Event
* @param event
*/
deleteEvent(event)
{
this.confirmDialogRef = this.dialog.open(FuseConfirmDialogComponent, {
disableClose: false
});
this.confirmDialogRef.componentInstance.confirmMessage = 'Are you sure you want to delete?';
this.confirmDialogRef.afterClosed().subscribe(result => {
if ( result )
{
const eventIndex = this.events.indexOf(event);
this.events.splice(eventIndex, 1);
this.refresh.next(true);
}
this.confirmDialogRef = null;
});
}
/**
* Edit Event
* @param {string} action
* @param {CalendarEvent} event
*/
editEvent(action: string, event: CalendarEvent)
{
const eventIndex = this.events.indexOf(event);
this.dialogRef = this.dialog.open(FuseCalendarEventFormDialogComponent, {
panelClass: 'event-form-dialog',
data : {
event : event,
action: action
}
});
this.dialogRef.afterClosed()
.subscribe(response => {
if ( !response )
{
return;
}
const actionType: string = response[0];
const formData: FormGroup = response[1];
switch ( actionType )
{
/**
* Save
*/
case 'save':
this.events[eventIndex] = Object.assign(this.events[eventIndex], formData.getRawValue());
this.refresh.next(true);
break;
/**
* Delete
*/
case 'delete':
this.deleteEvent(event);
break;
}
});
}
/**
* Add Event
*/
addEvent(): void
{
this.dialogRef = this.dialog.open(FuseCalendarEventFormDialogComponent, {
panelClass: 'event-form-dialog',
data : {
action: 'new',
date : this.selectedDay.date
}
});
this.dialogRef.afterClosed()
.subscribe((response: FormGroup) => {
if ( !response )
{
return;
}
const newEvent = response.getRawValue();
newEvent.actions = this.actions;
this.events.push(newEvent);
this.refresh.next(true);
});
}
}

View File

@@ -0,0 +1,37 @@
import { NgModule } from '@angular/core';
import { SharedModule } from '../../../../core/modules/shared.module';
import { RouterModule, Routes } from '@angular/router';
import { FuseCalendarComponent } from './calendar.component';
import { CalendarService } from './calendar.service';
import { CalendarModule } from 'angular-calendar';
import { FuseCalendarEventFormDialogComponent } from './event-form/event-form.component';
const routes: Routes = [
{
path : '**',
component: FuseCalendarComponent,
children : [],
resolve : {
chat: CalendarService
}
}
];
@NgModule({
imports : [
SharedModule,
RouterModule.forChild(routes),
CalendarModule.forRoot()
],
declarations : [
FuseCalendarComponent,
FuseCalendarEventFormDialogComponent
],
providers : [
CalendarService
],
entryComponents: [FuseCalendarEventFormDialogComponent]
})
export class FuseCalendarModule
{
}

View File

@@ -0,0 +1,58 @@
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';
@Injectable()
export class CalendarService implements Resolve<any>
{
events: any;
onEventsUpdated = new Subject<any>();
constructor(private http: Http)
{
}
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> | Promise<any> | any
{
return new Promise((resolve, reject) => {
Promise.all([
this.getEvents()
]).then(
([events]: [any]) => {
resolve();
},
reject
);
});
}
getEvents()
{
return new Promise((resolve, reject) => {
this.http.get('api/calendar/events')
.subscribe(response => {
this.events = response.json().data.data;
this.onEventsUpdated.next(this.events);
resolve(this.events);
}, reject);
});
}
updateEvents(events)
{
return new Promise((resolve, reject) => {
this.http.post('api/calendar/events', {
id : 'events',
data: [...events]
})
.subscribe(response => {
this.getEvents();
}, reject);
});
}
}

View File

@@ -0,0 +1,138 @@
<div class="dialog-content-wrapper">
<md-toolbar md-dialog-title class="mat-accent m-0">
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center">
<span class="title dialog-title">{{dialogTitle}}</span>
<button md-button class="mat-icon-button"
(click)="dialogRef.close()"
aria-label="Close dialog">
<md-icon>close</md-icon>
</button>
</div>
</md-toolbar>
<div md-dialog-content class="p-24 m-0" fusePerfectScrollbar>
<form name="eventForm" [formGroup]="eventForm" class="event-form w-100-p" fxLayout="column" fxFlex>
<md-input-container class="w-100-p">
<input mdInput
name="title"
formControlName="title"
placeholder="Title"
required>
</md-input-container>
<div class="py-16" fxFlex="1 0 auto" fxLayout="row">
<md-slide-toggle
name="allDay"
formControlName="allDay"
class="mr-24"
aria-label="All day">
All Day
</md-slide-toggle>
</div>
<div class="py-16" fxFlex="1 0 auto" fxLayout="row" formGroupName="color">
<md-input-container class="mr-24" fxFlex>
<input mdInput
name="primary color"
formControlName="primary"
placeholder="Primary color"
[(colorPicker)]="event.color.primary"
cpWidth="290px"
[cpPresetColors]="presetColors"
[style.background]="event.color.primary"
(colorPickerChange)="event.color.primary = $event; eventForm.patchValue({color:{primary:$event}})"/>
</md-input-container>
<md-input-container fxFlex>
<input mdInput
name="secondary color"
formControlName="secondary"
placeholder="Secondary color"
[(colorPicker)]="event.color.secondary"
cpWidth="290px"
[cpPresetColors]="presetColors"
[style.background]="event.color.secondary"
(colorPickerChange)="event.color.secondary = $event; eventForm.patchValue({color:{secondary:$event}})"/>
</md-input-container>
</div>
<div fxFlex="1 0 auto" fxLayout="row">
<md-form-field class="mr-24" fxFlex>
<input mdInput [mdDatepicker]="startDatePicker" placeholder="Start Date">
<md-datepicker-toggle mdSuffix [for]="startDatePicker"></md-datepicker-toggle>
<md-datepicker #startDatePicker></md-datepicker>
</md-form-field>
<md-input-container class="no-errors-spacer" fxFlex md-no-float>
<input mdInput placeholder="Start Time">
</md-input-container>
</div>
<div fxFlex="1 0 auto" fxLayout="row">
<md-form-field class="mr-24" fxFlex>
<input mdInput [mdDatepicker]="endDatePicker" placeholder="End Date">
<md-datepicker-toggle mdSuffix [for]="endDatePicker"></md-datepicker-toggle>
<md-datepicker #endDatePicker></md-datepicker>
</md-form-field>
<md-input-container class="no-errors-spacer" fxFlex md-no-float>
<input mdInput placeholder="End Time">
</md-input-container>
</div>
<md-input-container formGroupName="meta" class="w-100-p">
<input mdInput
name="location"
formControlName="location"
placeholder="Location">
</md-input-container>
<md-input-container formGroupName="meta" class="w-100-p">
<textarea mdInput
formControlName="notes"
placeholder="Notes"
md-maxlength="250"
max-rows="4">
</textarea>
</md-input-container>
</form>
</div>
<div md-dialog-actions class="m-0 p-16" fxLayout="row" fxLayoutAlign="space-between center">
<button *ngIf="action !=='edit'"
md-raised-button
(click)="dialogRef.close(eventForm)"
class="save-button mat-accent"
[disabled]="eventForm.invalid"
aria-label="SAVE">
SAVE
</button>
<button *ngIf="action ==='edit'"
md-raised-button
(click)="dialogRef.close(['save',eventForm])"
class="save-button mat-accent"
[disabled]="eventForm.invalid"
aria-label="SAVE">
SAVE
</button>
<button *ngIf="action ==='edit'"
md-button
class="mat-icon-button"
(click)="dialogRef.close(['delete',eventForm])"
aria-label="Delete"
md-tooltip="Delete">
<md-icon>delete</md-icon>
</button>
</div>
</div>

View File

@@ -0,0 +1,13 @@
.event-form-dialog {
.mat-dialog-container {
padding: 0;
width: 480px;
}
.dialog-content-wrapper {
max-height: 85vh;
display: flex;
flex-direction: column;
}
}

View File

@@ -0,0 +1,71 @@
import { Component, Inject, OnInit, ViewEncapsulation } from '@angular/core';
import { MD_DIALOG_DATA, MdDialogRef } from '@angular/material';
import { CalendarEvent } from 'angular-calendar';
import { FormBuilder, FormControl, FormGroup } from '@angular/forms';
import { CalendarEventModel } from '../event.model';
import { MatColors } from '../../../../../core/matColors';
import 'rxjs/Rx';
@Component({
selector : 'fuse-calendar-event-form-dialog',
templateUrl : './event-form.component.html',
styleUrls : ['./event-form.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class FuseCalendarEventFormDialogComponent implements OnInit
{
event: CalendarEvent;
dialogTitle: string;
eventForm: FormGroup;
action: string;
presetColors = MatColors.presets;
constructor(
public dialogRef: MdDialogRef<FuseCalendarEventFormDialogComponent>,
@Inject(MD_DIALOG_DATA) private data: any,
private formBuilder: FormBuilder
)
{
this.event = data.event;
this.action = data.action;
if ( this.action === 'edit' )
{
this.dialogTitle = this.event.title;
}
else
{
this.dialogTitle = 'New Event';
this.event = new CalendarEventModel({
start: data.date,
end : data.date
});
}
this.eventForm = this.createEventForm();
}
ngOnInit()
{
}
createEventForm()
{
return new FormGroup({
title : new FormControl(this.event.title),
start : new FormControl(this.event.start),
end : new FormControl(this.event.end),
allDay: new FormControl(this.event.allDay),
color : this.formBuilder.group({
primary : new FormControl(this.event.color.primary),
secondary: new FormControl(this.event.color.secondary)
}),
meta :
this.formBuilder.group({
location: new FormControl(this.event.meta.location),
notes : new FormControl(this.event.meta.notes)
})
});
}
}

View File

@@ -0,0 +1,74 @@
import {
CalendarEventAction
} from 'angular-calendar';
import {
startOfDay,
endOfDay,
subDays,
addDays,
endOfMonth,
isSameDay,
isSameMonth,
addHours
} from 'date-fns';
// import { CalendarEvent } from 'calendar-utils/dist/calendar-utils';
/*
export interface EventAction
{
label: string;
cssClass?: string;
onClick({event}: {
event: CalendarEvent;
}): any;
}*/
export class CalendarEventModel
{
start: Date;
end?: Date;
title: string;
color: {
primary: string;
secondary: string;
};
actions?: CalendarEventAction[];
allDay?: boolean;
cssClass?: string;
resizable?: {
beforeStart?: boolean;
afterEnd?: boolean;
};
draggable?: boolean;
meta?: {
location: string,
notes: string
};
constructor(data?)
{
data = data || {};
this.start = new Date(data.start) || startOfDay(new Date());
this.end = new Date(data.end) || endOfDay(new Date());
this.title = data.title || '';
this.color = {
primary : data.color && data.color.primary || '#1e90ff',
secondary: data.color && data.color.secondary || '#D1E8FF'
};
this.draggable = data.draggable || true;
this.resizable = {
beforeStart: data.resizable && data.resizable.beforeStart || true,
afterEnd : data.resizable && data.resizable.afterEnd || true
};
this.actions = data.actions || [];
this.allDay = data.allDay || false;
this.cssClass = data.cssClass || '';
this.meta = {
location: data.meta && data.meta.location || '',
notes : data.meta && data.meta.notes || ''
};
}
}

View File

@@ -0,0 +1,18 @@
<div fxFlex fxLayout="column" fxLayoutAlign="center center">
<div class="big-circle mat-elevation-z1 app-logo" fxLayout="column" fxLayoutAlign="center center"
*fuseIfOnDom [@animate]="{value:'*',params:{delay:'50ms',scale:'0.2'}}">
<md-icon class="s-64 s-md-128">chat</md-icon>
</div>
<span class="app-title my-24" *fuseIfOnDom [@animate]="{value:'*',params:{delay:'100ms',y:'25px'}}">Chat App</span>
<span fxHide fxShow.gt-md class="app-message" *fuseIfOnDom [@animate]="{value:'*',params:{delay:'200ms',y:'50px'}}">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>

View File

@@ -0,0 +1,35 @@
@import "src/app/core/scss/fuse";
:host {
display: flex;
flex: 1;
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;
@include media-breakpoint-down('sm') {
width: 160px;
height: 160px;
line-height: 160px;
}
md-icon {
color: mat-color($accent);
}
}
.app-title {
font-weight: 500;
font-size: 32px;
}
.secondary-text {
font-size: 16px;
}
}

View File

@@ -0,0 +1,21 @@
import { Component, OnInit } from '@angular/core';
import { fuseAnimations } from '../../../../../core/animations';
@Component({
selector : 'fuse-chat-start',
templateUrl: './chat-start.component.html',
styleUrls : ['./chat-start.component.scss'],
animations : fuseAnimations
})
export class FuseChatStartComponent implements OnInit
{
constructor()
{
}
ngOnInit()
{
}
}

View 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 fusePerfectScrollbar>
<!-- 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 -->

View File

@@ -0,0 +1,134 @@
:host {
display: flex;
flex: 1 0 auto;
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;
max-width: 100%;
.chat {
.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;
}
}
}
}
}

View 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 { FusePerfectScrollbarDirective } from '../../../../../core/directives/fuse-perfect-scrollbar/fuse-perfect-scrollbar.directive';
@Component({
selector : 'fuse-chat-view',
templateUrl: './chat-view.component.html',
styleUrls : ['./chat-view.component.scss']
})
export class FuseChatViewComponent implements OnInit, AfterViewInit
{
user: any;
chat: any;
dialog: any;
contact: any;
replyInput: any;
selectedChat: any;
@ViewChild(FusePerfectScrollbarDirective) directiveScroll: FusePerfectScrollbarDirective;
@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 )
{
this.directiveScroll.update();
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();
});
}
}

View File

@@ -0,0 +1,43 @@
<div id="chat" class="page-layout carded fullwidth">
<!-- 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>

View File

@@ -0,0 +1,51 @@
@import "src/app/core/scss/fuse";
#chat {
display: flex;
flex: 1;
.center {
padding: 32px !important;
max-width: 1400px;
margin: 0 auto;
@include media-breakpoint-down(md) {
padding: 0 !important;
}
.content-card {
display: flex;
flex: 1;
position: relative;
background: url('/assets/images/patterns/rain-grey.png') repeat;
.mat-sidenav-container {
display: flex;
flex: 1;
width: 100%;
background: transparent;
> .mat-sidenav-content,
> .mat-drawer-content {
display: flex;
flex: 1 1 auto;
min-height: 100%;
height: auto;
}
> .mat-drawer-content {
max-width: 100%;
}
md-sidenav {
display: flex;
flex-direction: column;
width: 400px;
max-width: 90%;
box-shadow: 0 0 1px rgba(0, 0, 0, .37);
overflow: hidden;
}
}
}
}
}

View File

@@ -0,0 +1,28 @@
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { ChatService } from './chat.service';
import { fuseAnimations } from '../../../../core/animations';
@Component({
selector : 'fuse-chat',
templateUrl : './chat.component.html',
styleUrls : ['./chat.component.scss'],
encapsulation: ViewEncapsulation.None,
animations : fuseAnimations
})
export class FuseChatComponent implements OnInit
{
selectedChat: any;
constructor(private chatService: ChatService)
{
}
ngOnInit()
{
this.chatService.onChatSelected
.subscribe(chatData => {
this.selectedChat = chatData;
});
}
}

View File

@@ -0,0 +1,46 @@
import { NgModule } from '@angular/core';
import { SharedModule } from '../../../../core/modules/shared.module';
import { RouterModule, Routes } from '@angular/router';
import { FuseChatComponent } from './chat.component';
import { ChatService } from './chat.service';
import { FuseChatViewComponent } from './chat-view/chat-view.component';
import { FuseChatStartComponent } from './chat-start/chat-start.component';
import { FuseChatChatsSidenavComponent } from './sidenavs/left/chats/chats.component';
import { FuseChatUserSidenavComponent } from './sidenavs/left/user/user.component';
import { FuseChatLeftSidenavComponent } from './sidenavs/left/left.component';
import { FuseChatRightSidenavComponent } from './sidenavs/right/right.component';
import { FuseChatContactSidenavComponent } from './sidenavs/right/contact/contact.component';
const routes: Routes = [
{
path : '**',
component: FuseChatComponent,
children : [],
resolve : {
chat: ChatService
}
}
];
@NgModule({
imports : [
SharedModule,
RouterModule.forChild(routes)
],
declarations: [
FuseChatComponent,
FuseChatViewComponent,
FuseChatStartComponent,
FuseChatChatsSidenavComponent,
FuseChatUserSidenavComponent,
FuseChatLeftSidenavComponent,
FuseChatRightSidenavComponent,
FuseChatContactSidenavComponent
],
providers : [
ChatService
]
})
export class FuseChatModule
{
}

View File

@@ -0,0 +1,247 @@
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';
import { FuseUtils } from '../../../../core/fuseUtils';
@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 = FuseUtils.generateGUID();
const chat = {
id : chatId,
dialog: []
};
const chatListItem = {
contactId : contactId,
id : chatId,
lastMessageTime: '2017-02-18T10:30:18.931Z',
name : contact.name,
unread : null
};
/**
* 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(newUserData => {
/**
* 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 Chat 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);
});
}
}

View 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)]="searchText" 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" fusePerfectScrollbar fxFlex>
<!-- CHATS CONTENT -->
<div *fuseIfOnDom [@animateStagger]="{value:'50'}">
<!-- CHATS LIST-->
<div class="chat-list" fxLayout="column">
<div md-subheader *ngIf="(user.chatList | filter: searchText).length > 0">
Chats
</div>
<button md-button class="contact"
*ngFor="let chat of user.chatList | filter: searchText"
(click)="getChat(chat.contactId)" ngClass="{'unread':contact.unread}"
[@animate]="{value:'*',params:{y:'100%'}}">
<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>
</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| filter: searchText).length > 0">
Contacts
</div>
<button md-button class="contact"
*ngFor="let contact of contacts| filter: searchText"
(click)="getChat(contact.id)"
[@animate]="{value:'*',params:{y:'100%'}}">
<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| filter: searchText).length === 0" class="no-results-message">
No results..
</div>
<!-- NO RESULTS MESSAGE-->
</div>
<!-- / CHATS CONTENT -->
</div>
<!-- / SIDENAV CONTENT -->

View File

@@ -0,0 +1,113 @@
@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 {
overflow: auto;
.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 {
line-height: normal;
margin-top: 0;
}
.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;
}
}
}

View File

@@ -0,0 +1,71 @@
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';
import { fuseAnimations } from '../../../../../../../core/animations';
@Component({
selector : 'fuse-chat-chats-sidenav',
templateUrl: './chats.component.html',
styleUrls : ['./chats.component.scss'],
animations : fuseAnimations
})
export class FuseChatChatsSidenavComponent implements OnInit
{
user: any;
chats: any[];
contacts: any[];
chatSearch: any;
searchText = '';
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.log('logout triggered');
}
}

View 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>

View 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;
}
}
}

View File

@@ -0,0 +1,27 @@
import { Component, OnInit } from '@angular/core';
import { fuseAnimations } from '../../../../../../core/animations';
import { ChatService } from '../../chat.service';
@Component({
selector : 'fuse-chat-left-sidenav',
templateUrl: './left.component.html',
styleUrls : ['./left.component.scss'],
animations : fuseAnimations
})
export class FuseChatLeftSidenavComponent implements OnInit
{
view: string;
constructor(private chatService: ChatService)
{
this.view = 'chats';
}
ngOnInit()
{
this.chatService.onLeftSidenavViewChanged.subscribe(view => {
this.view = view;
});
}
}

View File

@@ -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" fusePerfectScrollbar fxFlex>
<!-- USER MOOD -->
<md-card>
<form [formGroup]="userForm" fxLayout="column">
<md-input-container class="mb-24" fxFlex="0 1 auto">
<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>

View File

@@ -0,0 +1,25 @@
@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;
@include media-breakpoint-down(md) {
height: 180px;
}
}
}
.sidenav-content {
background: whitesmoke;
}
}

View 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 FuseChatUserSidenavComponent 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();
}
}

View File

@@ -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" fusePerfectScrollbar 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>

View File

@@ -0,0 +1,25 @@
@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;
@include media-breakpoint-down(md) {
height: 180px;
}
}
}
.sidenav-content {
background: whitesmoke;
}
}

View File

@@ -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 FuseChatContactSidenavComponent implements OnInit
{
contact: any;
constructor(private chatService: ChatService)
{
}
ngOnInit()
{
this.chatService.onContactSelected.subscribe(contact => {
this.contact = contact;
});
}
}

View File

@@ -0,0 +1,8 @@
<div [ngSwitch]="view" class="views">
<fuse-chat-contact-sidenav class="view"
*ngSwitchCase="'contact'"
[@slideInRight]>
</fuse-chat-contact-sidenav>
</div>

View 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;
}
}
}

View File

@@ -0,0 +1,27 @@
import { Component, OnInit } from '@angular/core';
import { fuseAnimations } from '../../../../../../core/animations';
import { ChatService } from '../../chat.service';
@Component({
selector : 'fuse-chat-right-sidenav',
templateUrl: './right.component.html',
styleUrls : ['./right.component.scss'],
animations : fuseAnimations
})
export class FuseChatRightSidenavComponent implements OnInit
{
view: string;
constructor(private chatService: ChatService)
{
this.view = 'contact';
}
ngOnInit()
{
this.chatService.onRightSidenavViewChanged.subscribe(view => {
this.view = view;
});
}
}

View File

@@ -0,0 +1,128 @@
<div class="dialog-content-wrapper">
<md-toolbar md-dialog-title class="mat-accent m-0">
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center">
<span class="title dialog-title">{{dialogTitle}}</span>
<button md-button class="mat-icon-button"
(click)="dialogRef.close()"
aria-label="Close dialog">
<md-icon>close</md-icon>
</button>
</div>
<md-toolbar-row class="toolbar-bottom py-8 py-sm-16" fxLayout="column" fxLayoutAlign="center center">
<img [src]="contact.avatar" class=" avatar contact-avatar huge"
[alt]="contact.name"/>
<div class="contact-name">{{contact.name}}</div>
</md-toolbar-row>
</md-toolbar>
<div md-dialog-content class="p-24 m-0" fusePerfectScrollbar>
<form [formGroup]="contactForm">
<div class="mb-24" fxLayout="row" fxLayoutAlign="start start">
<md-icon class="mr-12 mt-12">account_circle</md-icon>
<md-input-container fxFlex>
<input name="name" formControlName="name" placeholder="Name" mdInput required>
</md-input-container>
</div>
<div class="mb-24" fxLayout="row" fxLayoutAlign="start start">
<md-icon class="mr-12 mt-12"></md-icon>
<md-input-container fxFlex>
<input name="lastName" formControlName="lastName" placeholder="Lastname" mdInput>
</md-input-container>
</div>
<div class="mb-24" fxLayout="row" fxLayoutAlign="start start">
<md-icon class="mr-12 mt-12">star</md-icon>
<md-input-container fxFlex>
<input name="nickname" formControlName="nickname" mdInput placeholder="Nickname">
</md-input-container>
</div>
<div class="mb-24" fxLayout="row" fxLayoutAlign="start start">
<md-icon class="mr-12 mt-12">phone</md-icon>
<md-input-container fxFlex>
<input formControlName="phone" mdInput placeholder="Phone number">
</md-input-container>
</div>
<div class="mb-24" fxLayout="row" fxLayoutAlign="start start">
<md-icon class="mr-12 mt-12">email</md-icon>
<md-input-container fxFlex>
<input name="email" formControlName="email" mdInput type="email" placeholder="Email">
</md-input-container>
</div>
<div class="mb-24" fxLayout="row" fxLayoutAlign="start start">
<md-icon class="mr-12 mt-12">domain</md-icon>
<md-input-container fxFlex>
<input name="company" formControlName="company" mdInput placeholder="Company">
</md-input-container>
</div>
<div class="mb-24" fxLayout="row" fxLayoutAlign="start start">
<md-icon class="mr-12 mt-12">work</md-icon>
<md-input-container fxFlex>
<input name="jobTitle" formControlName="jobTitle" mdInput placeholder="Job title">
</md-input-container>
</div>
<div class="mb-24" fxLayout="row" fxLayoutAlign="start start">
<md-form-field class="mr-24" fxFlex>
<input mdInput [mdDatepicker]="birthdayDatePicker" placeholder="Birthday">
<md-datepicker-toggle mdSuffix [for]="birthdayDatePicker"></md-datepicker-toggle>
<md-datepicker #birthdayDatePicker></md-datepicker>
</md-form-field>
</div>
<div class="mb-24" fxLayout="row" fxLayoutAlign="start start">
<md-icon class="mr-12 mt-12">home</md-icon>
<md-input-container fxFlex>
<input name="address" formControlName="address" mdInput placeholder="Address">
</md-input-container>
</div>
<div fxLayout="row" class="textarea-wrapper" fxLayoutAlign="start start">
<md-icon class="mr-12 mt-12">note</md-icon>
<md-input-container fxFlex>
<textarea name="notes" formControlName="notes" placeholder="Notes" mdInput type="text" max-rows="4"></textarea>
</md-input-container>
</div>
</form>
</div>
<div md-dialog-actions class="m-0 p-16" fxLayout="row" fxLayoutAlign="space-between center">
<button *ngIf="action !=='edit'"
md-raised-button
(click)="dialogRef.close(contactForm)"
class="save-button mat-accent"
[disabled]="contactForm.invalid"
aria-label="SAVE">
SAVE
</button>
<button *ngIf="action ==='edit'"
md-raised-button
(click)="dialogRef.close(['save',contactForm])"
class="save-button mat-accent"
[disabled]="contactForm.invalid"
aria-label="SAVE">
SAVE
</button>
<button *ngIf="action ==='edit'"
md-button
class="mat-icon-button"
(click)="dialogRef.close(['delete',contactForm])"
aria-label="Delete"
md-tooltip="Delete">
<md-icon>delete</md-icon>
</button>
</div>
</div>

View File

@@ -0,0 +1,22 @@
.contact-form-dialog {
.mat-dialog-container {
padding: 0;
width: 400px;
overflow: hidden;
.mat-toolbar {
min-height: initial;
}
.toolbar-bottom {
height: auto;
}
}
.dialog-content-wrapper {
max-height: 85vh;
display: flex;
flex-direction: column;
}
}

View File

@@ -0,0 +1,66 @@
import { Component, Inject, OnInit, ViewEncapsulation } from '@angular/core';
import { MD_DIALOG_DATA, MdDialogRef } from '@angular/material';
import { CalendarEvent } from 'angular-calendar';
import { FormBuilder, FormGroup } from '@angular/forms';
import 'rxjs/Rx';
import { Contact } from '../contact.model';
@Component({
selector : 'fuse-contacts-contact-form-dialog',
templateUrl : './contact-form.component.html',
styleUrls : ['./contact-form.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class FuseContactsContactFormDialogComponent implements OnInit
{
event: CalendarEvent;
dialogTitle: string;
contactForm: FormGroup;
action: string;
contact: Contact;
constructor(
public dialogRef: MdDialogRef<FuseContactsContactFormDialogComponent>,
@Inject(MD_DIALOG_DATA) private data: any,
private formBuilder: FormBuilder
)
{
this.action = data.action;
if ( this.action === 'edit' )
{
this.dialogTitle = 'Edit Contact';
this.contact = data.contact;
}
else
{
this.dialogTitle = 'New Contact';
this.contact = new Contact({});
}
this.contactForm = this.createContactForm();
}
ngOnInit()
{
}
createContactForm()
{
return this.formBuilder.group({
id : [this.contact.id],
name : [this.contact.name],
lastName: [this.contact.lastName],
avatar : [this.contact.avatar],
nickname: [this.contact.nickname],
company : [this.contact.company],
jobTitle: [this.contact.jobTitle],
email : [this.contact.email],
phone : [this.contact.phone],
address : [this.contact.address],
birthday: [this.contact.birthday],
notes : [this.contact.notes]
});
}
}

View File

@@ -0,0 +1,106 @@
<md-table #table [dataSource]="dataSource"
[@animateStagger]="{value:'50'}">
<!-- Checkbox Column -->
<ng-container cdkColumnDef="checkbox">
<md-header-cell *cdkHeaderCellDef></md-header-cell>
<md-cell *cdkCellDef="let contact">
<md-checkbox [(ngModel)]="checkboxes[contact.id]" (ngModelChange)="onSelectedChange(contact.id)"
(click)="$event.stopPropagation()">
</md-checkbox>
</md-cell>
</ng-container>
<!-- Avatar Column -->
<ng-container cdkColumnDef="avatar">
<md-header-cell *cdkHeaderCellDef></md-header-cell>
<md-cell *cdkCellDef="let contact">
<img class="avatar" *ngIf="contact.avatar" [alt]="contact.name"
[src]="contact.avatar"/>
</md-cell>
</ng-container>
<!-- Name Column -->
<ng-container cdkColumnDef="name">
<md-header-cell *cdkHeaderCellDef>Name</md-header-cell>
<md-cell *cdkCellDef="let contact">
<p class="text-truncate font-weight-600">{{contact.name}} {{contact.lastName}}</p>
</md-cell>
</ng-container>
<!-- Email Column -->
<ng-container cdkColumnDef="email">
<md-header-cell *cdkHeaderCellDef fxHide fxShow.gt-sm>Email</md-header-cell>
<md-cell *cdkCellDef="let contact" fxHide fxShow.gt-sm>
<p class="email text-truncate">
{{contact.email}}
</p>
</md-cell>
</ng-container>
<!-- Phone Column -->
<ng-container cdkColumnDef="phone">
<md-header-cell *cdkHeaderCellDef fxHide fxShow.gt-md>Phone</md-header-cell>
<md-cell *cdkCellDef="let contact" fxHide fxShow.gt-md>
<p class="phone text-truncate">
{{contact.phone}}
</p>
</md-cell>
</ng-container>
<!-- Job Title Column -->
<ng-container cdkColumnDef="jobTitle">
<md-header-cell *cdkHeaderCellDef fxHide fxShow.gt-lg>Job title</md-header-cell>
<md-cell *cdkCellDef="let contact" fxHide fxShow.gt-lg>
<p class="job-title text-truncate">
{{contact.jobTitle}}
</p>
</md-cell>
</ng-container>
<!-- Company Column -->
<ng-container cdkColumnDef="company">
<md-header-cell *cdkHeaderCellDef fxHide fxShow.gt-lg>Company</md-header-cell>
<md-cell *cdkCellDef="let contact" fxHide fxShow.gt-lg>
<p class="company text-truncate">
{{contact.company}}
</p>
</md-cell>
</ng-container>
<!-- Buttons Column -->
<ng-container cdkColumnDef="buttons">
<md-header-cell *cdkHeaderCellDef></md-header-cell>
<md-cell *cdkCellDef="let contact">
<div fxFlex="row" fxLayoutAlign="end center">
<button md-icon-button (click)="$event.stopPropagation();toggleStar(contact.id)" aria-label="Toggle star">
<md-icon *ngIf="user.starred.includes(contact.id)">star</md-icon>
<md-icon *ngIf="!user.starred.includes(contact.id)">star_outline</md-icon>
</button>
<button md-icon-button [mdMenuTriggerFor]="moreMenu" aria-label="More"
(click)="$event.stopPropagation();">
<md-icon>more_vert</md-icon>
</button>
<md-menu #moreMenu="mdMenu">
<button md-menu-item aria-label="remove" (click)="deleteContact(contact)">
<md-icon>delete</md-icon>
<span>Remove</span>
</button>
</md-menu>
</div>
</md-cell>
</ng-container>
<md-header-row *cdkHeaderRowDef="displayedColumns"></md-header-row>
<md-row *cdkRowDef="let contact; columns: displayedColumns;"
class="contact"
(click)="editContact(contact)"
[ngClass]="{'md-light-blue-50-bg':checkboxes[contact.id]}"
md-ripple
[@animate]="{value:'*',params:{y:'100%'}}">
</md-row>
</md-table>

View File

@@ -0,0 +1,51 @@
@import "src/app/core/scss/fuse";
:host {
flex: 1;
.mat-table {
background: transparent;
box-shadow: none;
.mat-column-checkbox {
flex: 0 1 48px;
}
.mat-column-avatar {
flex: 0 1 64px;
}
.mat-column-buttons {
flex: 0 1 80px;
}
.mat-row {
position: relative;
cursor: pointer;
padding-right: 8px;
.mat-cell {
min-width: 0;
&.mat-column-detail-button {
flex: 0 1 auto;
padding: 0 24px 0 0;
@include media-breakpoint('gt-md') {
display: none;
}
}
}
}
}
}
#add-contact-button {
position: fixed;
bottom: 12px;
right: 12px;
padding: 0;
@include media-breakpoint-down('xs') {
top: 12px;
}
}

View File

@@ -0,0 +1,163 @@
import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { ContactsService } from '../contacts.service';
import { Observable } from 'rxjs/Observable';
import { FuseContactsContactFormDialogComponent } from '../contact-form/contact-form.component';
import { MdDialog, MdDialogRef } from '@angular/material';
import { FuseConfirmDialogComponent } from '../../../../../core/components/confirm-dialog/confirm-dialog.component';
import { FormGroup } from '@angular/forms';
import { DataSource } from '@angular/cdk/collections';
import { fuseAnimations } from '../../../../../core/animations';
@Component({
selector : 'fuse-contacts-contact-list',
templateUrl: './contact-list.component.html',
styleUrls : ['./contact-list.component.scss'],
animations : fuseAnimations
})
export class FuseContactsContactListComponent implements OnInit
{
@ViewChild('dialogContent') dialogContent: TemplateRef<any>;
contacts: any;
user: any;
dataSource: FilesDataSource | null;
displayedColumns = ['checkbox', 'avatar', 'name', 'email', 'phone', 'jobTitle', 'buttons'];
selectedContacts: any[];
checkboxes: {};
dialogRef: any;
confirmDialogRef: MdDialogRef<FuseConfirmDialogComponent>;
constructor(
private contactsService: ContactsService,
public dialog: MdDialog
)
{
this.contactsService.onContactsChanged.subscribe(contacts => {
this.contacts = contacts;
this.checkboxes = {};
contacts.map(contact => {
this.checkboxes[contact.id] = false;
});
});
this.contactsService.onSelectedContactsChanged.subscribe(selectedContacts => {
for ( const id in this.checkboxes )
{
this.checkboxes[id] = selectedContacts.includes(id);
}
this.selectedContacts = selectedContacts;
});
this.contactsService.onUserDataChanged.subscribe(user => {
this.user = user;
});
}
ngOnInit()
{
this.dataSource = new FilesDataSource(this.contactsService);
}
editContact(contact)
{
this.dialogRef = this.dialog.open(FuseContactsContactFormDialogComponent, {
panelClass: 'contact-form-dialog',
data : {
contact: contact,
action : 'edit'
}
});
this.dialogRef.afterClosed()
.subscribe(response => {
if ( !response )
{
return;
}
const actionType: string = response[0];
const formData: FormGroup = response[1];
switch ( actionType )
{
/**
* Save
*/
case 'save':
this.contactsService.updateContact(formData.getRawValue());
break;
/**
* Delete
*/
case 'delete':
this.deleteContact(contact);
break;
}
});
}
/**
* Delete Contact
*/
deleteContact(contact)
{
this.confirmDialogRef = this.dialog.open(FuseConfirmDialogComponent, {
disableClose: false
});
this.confirmDialogRef.componentInstance.confirmMessage = 'Are you sure you want to delete?';
this.confirmDialogRef.afterClosed().subscribe(result => {
if ( result )
{
this.contactsService.deleteContact(contact);
}
this.confirmDialogRef = null;
});
}
onSelectedChange(contactId)
{
this.contactsService.toggleSelectedContact(contactId);
}
toggleStar(contactId)
{
if ( this.user.starred.includes(contactId) )
{
this.user.starred.splice(this.user.starred.indexOf(contactId), 1);
}
else
{
this.user.starred.push(contactId);
}
this.contactsService.updateUserData(this.user);
}
}
export class FilesDataSource extends DataSource<any>
{
constructor(private contactsService: ContactsService)
{
super();
}
/** Connect function called by the table to retrieve one stream containing the data to render. */
connect(): Observable<any[]>
{
return this.contactsService.onContactsChanged;
}
disconnect()
{
}
}

View File

@@ -0,0 +1,35 @@
import { FuseUtils } from '../../../../core/fuseUtils';
export class Contact
{
id: string;
name: string;
lastName: string;
avatar: string;
nickname: string;
company: string;
jobTitle: string;
email: string;
phone: string;
address: string;
birthday: string;
notes: string;
constructor(contact)
{
{
this.id = contact.id || FuseUtils.generateGUID();
this.name = contact.name || '';
this.lastName = contact.lastName || '';
this.avatar = contact.avatar || 'assets/images/avatars/profile.jpg';
this.nickname = contact.nickname || '';
this.company = contact.company || '';
this.jobTitle = contact.jobTitle || '';
this.email = contact.email || '';
this.phone = contact.phone || '';
this.address = contact.address || '';
this.birthday = contact.birhday || '';
this.notes = contact.notes || '';
}
}
}

View File

@@ -0,0 +1,76 @@
<div id="contacts" class="page-layout simple left-sidenav inner-sidenav">
<!-- HEADER -->
<div class="header md-accent-bg p-16 p-sm-24" fxLayout="column" fxLayoutAlign="start start"
fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="space-between center">
<!-- APP TITLE -->
<div fxLayout="row" fxLayoutAlign="start center">
<button md-button class="mat-icon-button sidenav-toggle mr-12"
fuseMdSidenavToggler="contacts-main-sidenav"
fxHide.gt-md>
<md-icon>menu</md-icon>
</button>
<div class="logo" fxLayout="row" fxLayoutAlign="start center">
<md-icon class="logo-icon mr-16" *fuseIfOnDom [@animate]="{value:'*',params:{delay:'50ms',scale:'0.2'}}">account_box</md-icon>
<span class="logo-text h1" *fuseIfOnDom [@animate]="{value:'*',params:{delay:'100ms',x:'-25px'}}">Contacts</span>
</div>
</div>
<!-- / APP TITLE -->
<!-- SEARCH -->
<div class="search-input-wrapper mt-16 ml-8 m-sm-0" fxLayout="row" fxLayoutAlign="start center">
<label for="search" class="mr-8">
<md-icon>search</md-icon>
</label>
<md-input-container md-no-float class="m-0" floatPlaceholder="never">
<input mdInput [formControl]="searchInput" id="search" placeholder="Search for anything">
</md-input-container>
</div>
<!-- / SEARCH -->
</div>
<!-- / HEADER -->
<!-- SELECTED BAR -->
<fuse-selected-bar class="md-accent-600-bg" *ngIf="hasSelectedContacts" [@slideInTop]></fuse-selected-bar>
<!-- / SELECTED BAR -->
<md-sidenav-container>
<!-- SIDENAV -->
<md-sidenav class="sidenav mat-sidenav-opened" align="start" opened="true" mode="side"
fuseMdSidenavHelper="contacts-main-sidenav" md-is-locked-open="gt-sm">
<fuse-contacts-main-sidenav *fuseIfOnDom [@animate]="{value:'*'}"></fuse-contacts-main-sidenav>
</md-sidenav>
<!-- / SIDENAV -->
<!-- CENTER -->
<div class="center p-24 pb-56 pr-sm-92" fusePerfectScrollbar>
<!-- CONTENT -->
<div class="content md-white-bg mat-elevation-z4">
<fuse-contacts-contact-list></fuse-contacts-contact-list>
</div>
<!-- / CONTENT -->
</div>
<!-- / CENTER -->
</md-sidenav-container>
</div>
<!-- ADD CONTACT BUTTON -->
<button md-fab class="md-accent-bg" id="add-contact-button" (click)="newContact()" aria-label="add contact"
*fuseIfOnDom [@animate]="{value:'*', params:{delay:'300ms',scale:'.2'}}">
<md-icon>person_add</md-icon>
</button>
<!-- / ADD CONTACT BUTTON -->

View File

@@ -0,0 +1,13 @@
#contacts {
.content {
overflow: hidden;
}
}
#add-contact-button {
position: absolute;
bottom: 12px;
right: 12px;
padding: 0;
z-index: 99;
}

View File

@@ -0,0 +1,67 @@
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { ContactsService } from './contacts.service';
import { fuseAnimations } from '../../../../core/animations';
import { FormControl, FormGroup } from '@angular/forms';
import { FuseContactsContactFormDialogComponent } from './contact-form/contact-form.component';
import { MdDialog } from '@angular/material';
@Component({
selector : 'fuse-contacts',
templateUrl : './contacts.component.html',
styleUrls : ['./contacts.component.scss'],
encapsulation: ViewEncapsulation.None,
animations : fuseAnimations
})
export class FuseContactsComponent implements OnInit
{
hasSelectedContacts: boolean;
searchInput: FormControl;
dialogRef: any;
constructor(
private contactsService: ContactsService,
public dialog: MdDialog
)
{
this.searchInput = new FormControl('');
}
newContact()
{
this.dialogRef = this.dialog.open(FuseContactsContactFormDialogComponent, {
panelClass: 'contact-form-dialog',
data : {
action: 'new'
}
});
this.dialogRef.afterClosed()
.subscribe((response: FormGroup) => {
if ( !response )
{
return;
}
this.contactsService.updateContact(response.getRawValue());
});
}
ngOnInit()
{
this.contactsService.onSelectedContactsChanged
.subscribe(selectedContacts => {
this.hasSelectedContacts = selectedContacts.length > 0;
});
this.searchInput.valueChanges
.debounceTime(300)
.distinctUntilChanged()
.subscribe(searchText => {
this.contactsService.onSearchTextChanged.next(searchText);
});
}
}

View File

@@ -0,0 +1,40 @@
import { NgModule } from '@angular/core';
import { SharedModule } from '../../../../core/modules/shared.module';
import { RouterModule, Routes } from '@angular/router';
import { FuseContactsMainSidenavComponent } from './sidenavs/main/main.component';
import { FuseContactsComponent } from './contacts.component';
import { ContactsService } from './contacts.service';
import { FuseContactsContactListComponent } from './contact-list/contact-list.component';
import { FuseContactsSelectedBarComponent } from './selected-bar/selected-bar.component';
import { FuseContactsContactFormDialogComponent } from './contact-form/contact-form.component';
const routes: Routes = [
{
path : '**',
component: FuseContactsComponent,
resolve : {
contacts: ContactsService
}
}
];
@NgModule({
imports : [
SharedModule,
RouterModule.forChild(routes)
],
declarations : [
FuseContactsComponent,
FuseContactsContactListComponent,
FuseContactsSelectedBarComponent,
FuseContactsMainSidenavComponent,
FuseContactsContactFormDialogComponent
],
providers : [
ContactsService
],
entryComponents: [FuseContactsContactFormDialogComponent]
})
export class FuseContactsModule
{
}

View File

@@ -0,0 +1,238 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { Http } from '@angular/http';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Contact } from './contact.model';
import { FuseUtils } from '../../../../core/fuseUtils';
import { Subject } from 'rxjs/Subject';
@Injectable()
export class ContactsService implements Resolve<any>
{
onContactsChanged: BehaviorSubject<any> = new BehaviorSubject({});
onSelectedContactsChanged: BehaviorSubject<any> = new BehaviorSubject([]);
onUserDataChanged: BehaviorSubject<any> = new BehaviorSubject([]);
onSearchTextChanged: Subject<any> = new Subject();
onFilterChanged: Subject<any> = new Subject();
contacts: Contact[];
user: any;
selectedContacts: string[] = [];
searchText: string;
filterBy: string;
constructor(private http: Http)
{
}
/**
* The Contacts 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.getUserData()
]).then(
([files]) => {
this.onSearchTextChanged.subscribe(searchText => {
this.searchText = searchText;
this.getContacts();
});
this.onFilterChanged.subscribe(filter => {
this.filterBy = filter;
this.getContacts();
});
resolve();
},
reject
);
});
}
getContacts(): Promise<any>
{
return new Promise((resolve, reject) => {
this.http.get('api/contacts-contacts')
.subscribe(response => {
this.contacts = response.json().data;
if ( this.filterBy === 'starred' )
{
this.contacts = this.contacts.filter(_contact => {
return this.user.starred.includes(_contact.id);
});
}
if ( this.filterBy === 'frequent' )
{
this.contacts = this.contacts.filter(_contact => {
return this.user.frequentContacts.includes(_contact.id);
});
}
if ( this.searchText && this.searchText !== '' )
{
this.contacts = FuseUtils.filterArrayByString(this.contacts, this.searchText);
}
this.contacts = this.contacts.map(contact => {
return new Contact(contact);
});
this.onContactsChanged.next(this.contacts);
resolve(this.contacts);
}, reject);
}
);
}
getUserData(): Promise<any>
{
return new Promise((resolve, reject) => {
this.http.get('api/contacts-user/5725a6802d10e277a0f35724')
.subscribe(response => {
this.user = response.json().data;
this.onUserDataChanged.next(this.user);
resolve(this.user);
}, reject);
}
);
}
/**
* Toggle selected contact by id
* @param id
*/
toggleSelectedContact(id)
{
// First, check if we already have that todo as selected...
if ( this.selectedContacts.length > 0 )
{
const index = this.selectedContacts.indexOf(id);
if ( index !== -1 )
{
this.selectedContacts.splice(index, 1);
// Trigger the next event
this.onSelectedContactsChanged.next(this.selectedContacts);
// Return
return;
}
}
// If we don't have it, push as selected
this.selectedContacts.push(id);
// Trigger the next event
this.onSelectedContactsChanged.next(this.selectedContacts);
}
/**
* Toggle select all
*/
toggleSelectAll()
{
if ( this.selectedContacts.length > 0 )
{
this.deselectContacts();
}
else
{
this.selectContacts();
}
}
selectContacts(filterParameter?, filterValue?)
{
this.selectedContacts = [];
// If there is no filter, select all todos
if ( filterParameter === undefined || filterValue === undefined )
{
this.selectedContacts = [];
this.contacts.map(contact => {
this.selectedContacts.push(contact.id);
});
}
else
{
/* this.selectedContacts.push(...
this.contacts.filter(todo => {
return todo[filterParameter] === filterValue;
})
);*/
}
// Trigger the next event
this.onSelectedContactsChanged.next(this.selectedContacts);
}
updateContact(contact)
{
return new Promise((resolve, reject) => {
this.http.post('api/contacts-contacts/' + contact.id, {...contact})
.subscribe(response => {
this.getContacts();
resolve(response);
});
});
}
updateUserData(userData)
{
return new Promise((resolve, reject) => {
this.http.post('api/contacts-user/' + this.user.id, {...userData})
.subscribe(response => {
this.getUserData();
this.getContacts();
resolve(response);
});
});
}
deselectContacts()
{
this.selectedContacts = [];
// Trigger the next event
this.onSelectedContactsChanged.next(this.selectedContacts);
}
deleteContact(contact)
{
const contactIndex = this.contacts.indexOf(contact);
this.contacts.splice(contactIndex, 1);
this.onContactsChanged.next(this.contacts);
}
deleteSelectedContacts()
{
for ( const contactId of this.selectedContacts )
{
const contact = this.contacts.find(_contact => {
return _contact.id === contactId;
});
const contactIndex = this.contacts.indexOf(contact);
this.contacts.splice(contactIndex, 1);
}
this.onContactsChanged.next(this.contacts);
this.deselectContacts();
}
}

View File

@@ -0,0 +1,36 @@
<div fxFlex fxLayout="row" fxLayoutAlign="start center" class="p-24">
<div class="close-button-wrapper" fxFlex="0 1 auto" fxFlex.gt-sm="220px" (click)="deselectAll()">
<button class="p-8" md-button fxLayout="row" fxLayoutAlign="start center">
<md-icon class="mr-8">arrow_back</md-icon>
<span class="text-uppercase">Back</span>
</button>
</div>
<div fxFlex fxLayout="row" fxLayoutAlign="end center" fxLayoutAlign.gt-sm="space-between center">
<div>
<span class="selected-contacts-count">
<span>{{selectedContacts.length}}</span>
<span>selected</span>
</span>
<button md-icon-button [mdMenuTriggerFor]="selectMenu">
<md-icon>arrow_drop_down</md-icon>
</button>
<md-menu #selectMenu="mdMenu">
<button md-menu-item (click)="selectAll()">Select all</button>
<button md-menu-item (click)="deselectAll()">Deselect all</button>
</md-menu>
</div>
<div class="multi-select-actions">
<button md-icon-button (click)="deleteSelectedContacts()" aria-label="delete selected">
<md-icon>delete</md-icon>
</button>
</div>
</div>
</div>

View File

@@ -0,0 +1,11 @@
@import "src/app/core/scss/fuse";
:host {
flex: 1;
position: absolute;
top: 0;
right: 0;
left: 0;
height: 120px;
z-index: 99;
}

Some files were not shown because too many files have changed in this diff Show More