(Contacts App) ongoing

This commit is contained in:
mustafahlvc 2017-08-02 19:51:02 +03:00
parent ccfd711c03
commit c4a08dc939
20 changed files with 583 additions and 107 deletions

View File

@ -3,20 +3,66 @@ import { trigger, state, transition, animate, style } from '@angular/animations'
export class Animations export class Animations
{ {
public static slideInOut = trigger('slideInOut', [ public static slideInOut = trigger('slideInOut', [
state('0', style({height: '0px', display: 'none'})), state('0', style({
state('1', style({height: '*', display: 'block'})), height : '0px',
display: 'none'
})),
state('1', style({
height : '*',
display: 'block'
})),
transition('1 => 0', animate('300ms ease-out')), transition('1 => 0', animate('300ms ease-out')),
transition('0 => 1', animate('300ms ease-in')) transition('0 => 1', animate('300ms ease-in'))
]); ]);
public static slideInLeft = trigger('slideInLeft', [ public static slideInLeft = trigger('slideInLeft', [
state('void', style({transform: 'translateX(-100%)', display: 'none'})), state('void', style({
state('*', style({transform: 'translateX(0)', display: 'flex'})), transform: 'translateX(-100%)',
display : 'none'
})),
state('*', style({
transform: 'translateX(0)',
display : 'flex'
})),
transition('void => *', animate('300ms')), transition('void => *', animate('300ms')),
transition('* => void', animate('300ms')) transition('* => void', animate('300ms'))
]); ]);
public static slideInRight = trigger('slideInRight', [ public static slideInRight = trigger('slideInRight', [
state('void', style({transform: 'translateX(100%)', display: 'none'})), state('void', style({
state('*', style({transform: 'translateX(0)', display: 'flex'})), transform: 'translateX(100%)',
display : 'none'
})),
state('*', style({
transform: 'translateX(0)',
display : 'flex'
})),
transition('void => *', animate('300ms')),
transition('* => void', animate('300ms'))
]);
public static slideInTop = trigger('slideInTop', [
state('void', style({
transform: 'translateY(-100%)',
display : 'none'
})),
state('*', style({
transform: 'translateY(0)',
display : 'flex'
})),
transition('void => *', animate('300ms')),
transition('* => void', animate('300ms'))
]);
public static slideInBottom = trigger('slideInBottom', [
state('void', style({
transform: 'translateY(100%)',
display : 'none'
})),
state('*', style({
transform: 'translateY(0)',
display : 'flex'
})),
transition('void => *', animate('300ms')), transition('void => *', animate('300ms')),
transition('* => void', animate('300ms')) transition('* => void', animate('300ms'))
]); ]);

View File

@ -308,6 +308,7 @@ $carded-header-height-without-toolbar-sm: $carded-header-height-sm - $carded-too
&.inner-sidenav { &.inner-sidenav {
> md-sidenav-container { > md-sidenav-container {
flex: 1;
.sidenav { .sidenav {
@ -332,7 +333,6 @@ $carded-header-height-without-toolbar-sm: $carded-header-height-sm - $carded-too
.content { .content {
display: flex; display: flex;
flex: 1; flex: 1;
min-height: 100%;
} }
} }
} }

View File

@ -352,4 +352,60 @@ export class ContactsFakeDb
'notes' : '' '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

@ -30,6 +30,7 @@ export class FuseFakeDbService implements InMemoryDbService
'profile-photos-videos': ProfileFakeDb.photosVideos, 'profile-photos-videos': ProfileFakeDb.photosVideos,
'profile-about' : ProfileFakeDb.about, 'profile-about' : ProfileFakeDb.about,
'contacts-contacts' : ContactsFakeDb.contacts, 'contacts-contacts' : ContactsFakeDb.contacts,
'contacts-user' : ContactsFakeDb.user,
'invoice' : InvoiceFakeDb.invoice, 'invoice' : InvoiceFakeDb.invoice,
'file-manager' : FileManagerFakeDb.files, 'file-manager' : FileManagerFakeDb.files,
'search-classic' : SearchFakeDb.classic, 'search-classic' : SearchFakeDb.classic,

View File

@ -4,13 +4,15 @@
<ng-container cdkColumnDef="checkbox"> <ng-container cdkColumnDef="checkbox">
<md-header-cell *cdkHeaderCellDef></md-header-cell> <md-header-cell *cdkHeaderCellDef></md-header-cell>
<md-cell *cdkCellDef="let contact"> <md-cell *cdkCellDef="let contact">
Check <md-checkbox [(ngModel)]="checkboxes[contact.id]" (ngModelChange)="onSelectedChange(contact.id)"
(click)="$event.stopPropagation()">
</md-checkbox>
</md-cell> </md-cell>
</ng-container> </ng-container>
<!-- Avatar Column --> <!-- Avatar Column -->
<ng-container cdkColumnDef="avatar"> <ng-container cdkColumnDef="avatar">
<md-header-cell *cdkHeaderCellDef>Name</md-header-cell> <md-header-cell *cdkHeaderCellDef></md-header-cell>
<md-cell *cdkCellDef="let contact"> <md-cell *cdkCellDef="let contact">
<img class="avatar" *ngIf="contact.avatar" [alt]="contact.name" <img class="avatar" *ngIf="contact.avatar" [alt]="contact.name"
[src]="contact.avatar"/> [src]="contact.avatar"/>
@ -27,9 +29,9 @@
<!-- Email Column --> <!-- Email Column -->
<ng-container cdkColumnDef="email"> <ng-container cdkColumnDef="email">
<md-header-cell *cdkHeaderCellDef>Email</md-header-cell> <md-header-cell *cdkHeaderCellDef fxHide fxShow.gt-sm>Email</md-header-cell>
<md-cell *cdkCellDef="let contact"> <md-cell *cdkCellDef="let contact" fxHide fxShow.gt-sm>
<p class="email text-truncate" fxShow.gt-sm> <p class="email text-truncate">
{{contact.email}} {{contact.email}}
</p> </p>
</md-cell> </md-cell>
@ -37,9 +39,9 @@
<!-- Phone Column --> <!-- Phone Column -->
<ng-container cdkColumnDef="phone"> <ng-container cdkColumnDef="phone">
<md-header-cell *cdkHeaderCellDef>Phone</md-header-cell> <md-header-cell *cdkHeaderCellDef fxHide fxShow.gt-md>Phone</md-header-cell>
<md-cell *cdkCellDef="let contact"> <md-cell *cdkCellDef="let contact" fxHide fxShow.gt-md>
<p class="phone text-truncate" fxShow.gt-md> <p class="phone text-truncate">
{{contact.phone}} {{contact.phone}}
</p> </p>
</md-cell> </md-cell>
@ -47,9 +49,9 @@
<!-- Job Title Column --> <!-- Job Title Column -->
<ng-container cdkColumnDef="jobTitle"> <ng-container cdkColumnDef="jobTitle">
<md-header-cell *cdkHeaderCellDef>Job title</md-header-cell> <md-header-cell *cdkHeaderCellDef fxHide fxShow.gt-lg>Job title</md-header-cell>
<md-cell *cdkCellDef="let contact"> <md-cell *cdkCellDef="let contact" fxHide fxShow.gt-lg>
<p class="job-title text-truncate" fxShow.gt-lg> <p class="job-title text-truncate">
{{contact.jobTitle}} {{contact.jobTitle}}
</p> </p>
</md-cell> </md-cell>
@ -57,9 +59,9 @@
<!-- Company Column --> <!-- Company Column -->
<ng-container cdkColumnDef="company"> <ng-container cdkColumnDef="company">
<md-header-cell *cdkHeaderCellDef>Company</md-header-cell> <md-header-cell *cdkHeaderCellDef fxHide fxShow.gt-lg>Company</md-header-cell>
<md-cell *cdkCellDef="let contact"> <md-cell *cdkCellDef="let contact" fxHide fxShow.gt-lg>
<p class="company text-truncate" fxShow.gt-lg> <p class="company text-truncate">
{{contact.company}} {{contact.company}}
</p> </p>
</md-cell> </md-cell>
@ -68,15 +70,33 @@
<!-- Buttons Column --> <!-- Buttons Column -->
<ng-container cdkColumnDef="buttons"> <ng-container cdkColumnDef="buttons">
<md-header-cell *cdkHeaderCellDef></md-header-cell> <md-header-cell *cdkHeaderCellDef></md-header-cell>
<md-cell *cdkCellDef="let row"> <md-cell *cdkCellDef="let contact">
Buttons <div fxFlex="row" fxLayoutAlign="end center">
<button md-icon-button (click)="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"
ng-click="$mdOpenMenu($event)">
<md-icon>more_vert</md-icon>
</button>
<md-menu #moreMenu="mdMenu">
<button md-menu-item aria-label="remove" (click)="removeContact(contact.id)">
<md-icon>delete</md-icon>
<span>Remove</span>
</button>
</md-menu>
</div>
</md-cell> </md-cell>
</ng-container> </ng-container>
<md-header-row *cdkHeaderRowDef="displayedColumns"></md-header-row> <md-header-row *cdkHeaderRowDef="displayedColumns"></md-header-row>
<md-row *cdkRowDef="let row; columns: displayedColumns;" <md-row *cdkRowDef="let row; columns: displayedColumns;"
(click)="onSelect(row)" (click)="onSelect(row)"
[ngClass]="{'md-light-blue-50-bg':row == selected}" [ngClass]="{'md-light-blue-50-bg':checkboxes[row.id]}"
md-ripple> md-ripple>
</md-row> </md-row>
</md-table> </md-table>

View File

@ -1,20 +1,30 @@
@import "src/app/core/scss/fuse"; @import "src/app/core/scss/fuse";
:host { :host {
flex: 1;
.mat-table { .mat-table {
background: transparent; background: transparent;
box-shadow: none; box-shadow: none;
.mat-column-checkbox {
flex: 0 1 64px;
}
.mat-column-avatar {
flex: 0 1 64px;
}
.mat-column-buttons {
flex: 0 1 80px;
}
.mat-row { .mat-row {
position: relative; position: relative;
cursor: pointer; cursor: pointer;
.mat-cell { .mat-cell {
min-width: 0;
&.mat-column-icon {
flex: 0 1 auto;
padding: 0 24px 0 0;
}
&.mat-column-detail-button { &.mat-column-detail-button {
flex: 0 1 auto; flex: 0 1 auto;

View File

@ -11,28 +11,70 @@ import { Observable } from 'rxjs/Observable';
export class ContactListComponent implements OnInit export class ContactListComponent implements OnInit
{ {
contacts: any; contacts: any;
user: any;
dataSource: FilesDataSource | null; dataSource: FilesDataSource | null;
displayedColumns = ['checkbox', 'avatar', 'name', 'email', 'phone', 'jobTitle', 'buttons']; displayedColumns = ['checkbox', 'avatar', 'name', 'email', 'phone', 'jobTitle', 'buttons'];
selected: any; selectedContacts: any[];
checkboxes: {};
constructor(private fileManagerService: ContactsService) constructor(private contactsService: ContactsService)
{ {
this.fileManagerService.onContactsChanged.subscribe(files => { this.contactsService.onContactsChanged.subscribe(contacts => {
this.contacts = files;
this.contacts = contacts;
this.checkboxes = {};
contacts.map(contact => {
this.checkboxes[contact.id] = false;
}); });
this.fileManagerService.onContactSelected.subscribe(selected => {
this.selected = selected;
}); });
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() ngOnInit()
{ {
this.dataSource = new FilesDataSource(this.fileManagerService); this.dataSource = new FilesDataSource(this.contactsService);
} }
onSelect(selected) onSelect(selected)
{ {
this.fileManagerService.onContactSelected.next(selected); // this.fileManagerService.onContactSelected.next(selected);
}
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);
}
removeContact(contactId)
{
} }
} }

View File

@ -0,0 +1,35 @@
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;
this.name = contact.name;
this.lastName = contact.lastName;
this.avatar = contact.avatar;
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

@ -1,7 +1,7 @@
<div id="contacts" class="page-layout simple left-sidenav inner-sidenav" fxfxLayout="column"> <div id="contacts" class="page-layout simple left-sidenav inner-sidenav" fxLayout="column">
<!-- HEADER --> <!-- HEADER -->
<div class="header md-accent-bg p-24" fxfxLayout="row" fxLayoutAlign="space-between center"> <div class="header md-accent-bg p-24" fxLayout="row" fxLayoutAlign="space-between center">
<!-- APP TITLE --> <!-- APP TITLE -->
<div fxLayout="row" fxLayoutAlign="start center"> <div fxLayout="row" fxLayoutAlign="start center">
@ -26,7 +26,7 @@
<md-icon>search</md-icon> <md-icon>search</md-icon>
</label> </label>
<md-input-container md-no-float class="m-0" floatPlaceholder="never"> <md-input-container md-no-float class="m-0" floatPlaceholder="never">
<input mdInput id="search" placeholder="Search for anyone"> <input mdInput [formControl]="searchInput" id="search" placeholder="Search for anything">
</md-input-container> </md-input-container>
</div> </div>
<!-- / SEARCH --> <!-- / SEARCH -->
@ -34,15 +34,17 @@
</div> </div>
<!-- / HEADER --> <!-- / HEADER -->
<!-- SELECTED BAR -->
<fuse-selected-bar class="md-accent-600-bg" *ngIf="hasSelectedContacts" [@slideInTop]></fuse-selected-bar>
<!-- / SELECTED BAR -->
<md-sidenav-container> <md-sidenav-container>
<!-- SIDENAV --> <!-- SIDENAV -->
<md-sidenav class="sidenav mat-sidenav-opened" align="start" opened="true" mode="side" <md-sidenav class="sidenav mat-sidenav-opened" align="start" opened="true" mode="side"
fuseMdSidenavHelper="contacts-main-sidenav" md-is-locked-open="gt-md"> fuseMdSidenavHelper="contacts-main-sidenav" md-is-locked-open="gt-md">
<div class="sidenav-content" perfect-scrollbar>
<fuse-contacts-main-sidenav></fuse-contacts-main-sidenav> <fuse-contacts-main-sidenav></fuse-contacts-main-sidenav>
</div>
</md-sidenav> </md-sidenav>
<!-- / SIDENAV --> <!-- / SIDENAV -->
@ -51,7 +53,7 @@
<div class="center p-24" perfect-scrollbar> <div class="center p-24" perfect-scrollbar>
<!-- CONTENT --> <!-- CONTENT -->
<div class="content p-24 md-white-bg mat-elevation-z4"> <div class="content md-white-bg mat-elevation-z4">
<fuse-contacts-contact-list></fuse-contacts-contact-list> <fuse-contacts-contact-list></fuse-contacts-contact-list>

View File

@ -1,2 +1,5 @@
@import "src/app/core/scss/fuse"; @import "src/app/core/scss/fuse";
#contacts {
}

View File

@ -1,26 +1,38 @@
import { Component, OnInit, ViewEncapsulation } from '@angular/core'; import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { ContactsService } from './contacts.service'; import { ContactsService } from './contacts.service';
import { Animations } from '../../../../core/animations';
import { FormControl } from '@angular/forms';
@Component({ @Component({
selector : 'fuse-contacts', selector : 'fuse-contacts',
templateUrl : './contacts.component.html', templateUrl : './contacts.component.html',
styleUrls : ['./contacts.component.scss'], styleUrls : ['./contacts.component.scss'],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None,
animations : [Animations.slideInTop]
}) })
export class ContactsComponent implements OnInit export class ContactsComponent implements OnInit
{ {
hasSelectedContacts: boolean;
selected: any; searchInput: FormControl;
constructor(private contactsService: ContactsService) constructor(private contactsService: ContactsService)
{ {
this.searchInput = new FormControl('');
} }
ngOnInit() ngOnInit()
{ {
this.contactsService.onContactSelected.subscribe(selected => {
this.selected = selected; 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

@ -5,6 +5,7 @@ import { MainSidenavComponent } from './sidenavs/main/main.component';
import { ContactsComponent } from './contacts.component'; import { ContactsComponent } from './contacts.component';
import { ContactsService } from './contacts.service'; import { ContactsService } from './contacts.service';
import { ContactListComponent } from './contact-list/contact-list.component'; import { ContactListComponent } from './contact-list/contact-list.component';
import { SelectedBarComponent } from './selected-bar/selected-bar.component';
const routes: Routes = [ const routes: Routes = [
{ {
@ -25,6 +26,7 @@ const routes: Routes = [
declarations: [ declarations: [
ContactsComponent, ContactsComponent,
ContactListComponent, ContactListComponent,
SelectedBarComponent,
MainSidenavComponent MainSidenavComponent
], ],
providers : [ providers : [

View File

@ -3,12 +3,24 @@ import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/r
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import { Http } from '@angular/http'; import { Http } from '@angular/http';
import { BehaviorSubject } from 'rxjs/BehaviorSubject'; import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Contact } from './contact.model';
import { FuseUtils } from '../../../../core/fuseUtils';
import { Subject } from 'rxjs/Subject';
@Injectable() @Injectable()
export class ContactsService implements Resolve<any> export class ContactsService implements Resolve<any>
{ {
onContactsChanged: BehaviorSubject<any> = new BehaviorSubject({}); onContactsChanged: BehaviorSubject<any> = new BehaviorSubject({});
onContactSelected: BehaviorSubject<any> = new BehaviorSubject({});
onSelectedContactsChanged: BehaviorSubject<any> = new BehaviorSubject([]);
onUserDataChanged: BehaviorSubject<any> = new BehaviorSubject([]);
onSearchTextChanged: Subject<any> = new Subject();
contacts: Contact[];
user: any;
selectedContacts: string[] = [];
constructor(private http: Http) constructor(private http: Http)
{ {
@ -26,26 +38,159 @@ export class ContactsService implements Resolve<any>
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
Promise.all([ Promise.all([
this.getContacts() this.getContacts(),
this.getUserData()
]).then( ]).then(
([files]) => { ([files]) => {
this.onSearchTextChanged.subscribe(searchText => {
this.getContacts(searchText);
});
resolve(); resolve();
}, },
reject reject
); );
}); });
} }
getContacts(): Promise<any> getContacts(searchText?): Promise<any>
{ {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.http.get('api/contacts-contacts') this.http.get('api/contacts-contacts')
.subscribe(response => { .subscribe(response => {
this.onContactsChanged.next(response.json().data);
this.onContactSelected.next(response.json().data[0]); this.contacts = response.json().data;
resolve(response.json().data);
if ( searchText && searchText !== '' )
{
this.contacts = FuseUtils.filterArrayByString(this.contacts, searchText);
}
this.contacts = this.contacts.map(contact => {
return new Contact(contact);
});
this.onContactsChanged.next(this.contacts);
resolve(this.contacts);
}, reject); }, 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()
{
console.info(this.selectedContacts);
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 => {
resolve(response);
});
}); });
} }
updateUserData(userData)
{
return new Promise((resolve, reject) => {
this.http.post('api/contacts-user/' + this.user.id, {...userData})
.subscribe(response => {
this.getUserData();
resolve(response);
});
});
}
deselectContacts()
{
this.selectedContacts = [];
// Trigger the next event
this.onSelectedContactsChanged.next(this.selectedContacts);
}
} }

View File

@ -0,0 +1,37 @@
<div fxFlex fxLayout="row" fxLayoutAlign="start center" class="p-24">
<div class="close-button-wrapper" fxFlex="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="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($event)"
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;
}

View File

@ -0,0 +1,47 @@
import { Component, OnInit } from '@angular/core';
import { ContactsService } from '../contacts.service';
@Component({
selector : 'fuse-selected-bar',
templateUrl: './selected-bar.component.html',
styleUrls : ['./selected-bar.component.scss']
})
export class SelectedBarComponent implements OnInit
{
selectedContacts: string[];
hasSelectedContacts: boolean;
isIndeterminate: boolean;
constructor(private contactsService: ContactsService)
{
this.contactsService.onSelectedContactsChanged
.subscribe(selectedContacts => {
this.selectedContacts = selectedContacts;
setTimeout(() => {
this.hasSelectedContacts = selectedContacts.length > 0;
this.isIndeterminate = (selectedContacts.length !== this.contactsService.contacts.length && selectedContacts.length > 0);
}, 0);
});
}
ngOnInit()
{
}
selectAll()
{
this.contactsService.selectContacts();
}
deselectAll()
{
this.contactsService.deselectContacts();
}
deleteSelectedContacts()
{
}
}

View File

@ -1,54 +1,42 @@
<!-- SIDENAV HEADER --> <div class="sidenav-content p-24 pr-4">
<div class="header p-24" fxLayout="column" fxLayoutAlign="space-between">
<div class="card md-white-bg mat-elevation-z4">
<!-- SIDENAV HEADER -->
<div class="header p-24" fxLayout="row" fxLayoutAlign="start center">
<!-- USER -->
<img [src]="user.avatar" class="avatar mr-16" [alt]="user.name"/>
<span class="h5">{{user.name}}</span>
<!-- / USER -->
<div class="logo" fxLayout="row" fxLayoutAlign="start center">
<md-icon class="logo-icon mr-16">folder</md-icon>
<span class="logo-text h1">File Manager</span>
</div> </div>
<!-- / SIDENAV HEADER -->
</div> <!-- SIDENAV CONTENT -->
<!-- / SIDENAV HEADER --> <div class="content py-16" perfect-scrollbar>
<!-- SIDENAV CONTENT -->
<div class="content py-16" perfect-scrollbar>
<div class="nav"> <div class="nav">
<div class="nav-item" aria-label="inbox"> <div class="nav-item" aria-label="inbox">
<a class="nav-link" md-ripple> <a class="nav-link" md-ripple>
<md-icon class="nav-link-icon">folder</md-icon> <span class="title">All Contacts</span>
<span class="title">My Files</span>
</a> </a>
</div> </div>
<div class="nav-item" aria-label="starred"> <div class="nav-item" aria-label="starred">
<a class="nav-link" md-ripple> <a class="nav-link" md-ripple>
<md-icon class="nav-link-icon">star</md-icon> <div class="title">Freequently contacted</div>
<div class="title">Starred</div>
</a> </a>
</div> </div>
<div class="nav-item" aria-label="starred"> <div class="nav-item" aria-label="starred">
<a class="nav-link" md-ripple> <a class="nav-link" md-ripple>
<md-icon class="nav-link-icon">folder_shared</md-icon> <div class="title">Starred Contacts</div>
<div class="title">Sharred with me</div>
</a>
</div>
<div class="nav-item" aria-label="starred">
<a class="nav-link" md-ripple>
<md-icon class="nav-link-icon">access_time</md-icon>
<div class="title">Recent</div>
</a>
</div>
<div class="nav-item" aria-label="starred">
<a class="nav-link" md-ripple>
<md-icon class="nav-link-icon">not_interested</md-icon>
<div class="title">Offline</div>
</a> </a>
</div> </div>
</div> </div>
</div>
</div>
</div> </div>
<!-- / SIDENAV CONTENT --> <!-- / SIDENAV CONTENT -->

View File

@ -4,8 +4,23 @@
flex: 1 0 auto; flex: 1 0 auto;
height: 100%; height: 100%;
.sidenav-content {
display: flex;
flex-direction: column;
.card {
display: flex;
flex-direction: column;
flex: 0 1 auto;
> .header { > .header {
flex: 0 1 auto; flex: 0 1 auto;
border-bottom: 1px solid rgba(0, 0, 0, 0.12); border-bottom: 1px solid rgba(0, 0, 0, 0.12);
} }
> .content {
flex: 0 1 auto;
}
}
}
} }

View File

@ -1,4 +1,5 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { ContactsService } from '../../contacts.service';
@Component({ @Component({
selector : 'fuse-contacts-main-sidenav', selector : 'fuse-contacts-main-sidenav',
@ -7,11 +8,13 @@ import { Component, OnInit } from '@angular/core';
}) })
export class MainSidenavComponent implements OnInit export class MainSidenavComponent implements OnInit
{ {
selected: any; user: any;
constructor() constructor(private contactsService: ContactsService)
{ {
this.contactsService.onUserDataChanged.subscribe(user => {
this.user = user;
});
} }
ngOnInit() ngOnInit()

View File

@ -18,6 +18,7 @@ fuse-main {
display: flex; display: flex;
flex: 1; flex: 1;
flex-direction: column; flex-direction: column;
overflow: hidden;
#wrapper { #wrapper {
display: flex; display: flex;