diff --git a/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-side.component.html b/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-side.component.html index b4bda552..0358f4a2 100644 --- a/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-side.component.html +++ b/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-side.component.html @@ -44,4 +44,8 @@ + diff --git a/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-side.component.ts b/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-side.component.ts index 11447c9a..de430cb0 100644 --- a/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-side.component.ts +++ b/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-side.component.ts @@ -31,6 +31,9 @@ export class LeftSideComponent implements OnInit { /** 조직도에서 부서원 선택 */ selectedUserList: (UserInfo | UserInfoSS | UserInfoF | UserInfoDN)[] = []; + /** FAB */ + fabButtons: { icon: string }[]; + constructor( private store: Store, private dialogService: DialogService, @@ -41,6 +44,20 @@ export class LeftSideComponent implements OnInit { this.badgeChatUnReadCount$ = this.store.pipe( select(AppStore.MessengerSelector.SyncSelector.selectChatUnreadCount) ); + this.fabButtons = [ + { + icon: 'timeline' + }, + { + icon: 'view_headline' + }, + { + icon: 'room' + }, + { + icon: 'lock' + } + ]; } async onClickNewChat() { @@ -106,4 +123,9 @@ export class LeftSideComponent implements OnInit { ); } } + + /** FAB */ + onClickFab(params: { btn: { icon: string } }) { + this.logger.debug('FAB click', params.btn); + } } diff --git a/projects/ucap-webmessenger-ui/src/lib/animations/index.ts b/projects/ucap-webmessenger-ui/src/lib/animations/index.ts index ac5a437f..d734017b 100644 --- a/projects/ucap-webmessenger-ui/src/lib/animations/index.ts +++ b/projects/ucap-webmessenger-ui/src/lib/animations/index.ts @@ -10,7 +10,8 @@ import { state, animation, useAnimation, - stagger + stagger, + keyframes } from '@angular/animations'; const customAnimation = animation( @@ -548,5 +549,52 @@ export const ucapAnimations = [ query('content > :leave', animateChild(), { optional: true }) ]) ) + ]), + + /** + * Floating ACtion Button Animation. + */ + trigger('fabToggler', [ + state( + 'inactive', + style({ + transform: 'rotate(0deg)' + }) + ), + state( + 'active', + style({ + transform: 'rotate(225deg)' + }) + ), + transition('* <=> *', animate('200ms cubic-bezier(0.4, 0.0, 0.2, 1)')) + ]), + trigger('speedDialStagger', [ + transition('* => *', [ + query(':enter', style({ opacity: 0 }), { optional: true }), + + query( + ':enter', + stagger('40ms', [ + animate( + '200ms cubic-bezier(0.4, 0.0, 0.2, 1)', + keyframes([ + style({ opacity: 0, transform: 'translateY(10px)' }), + style({ opacity: 1, transform: 'translateY(0)' }) + ]) + ) + ]), + { optional: true } + ), + + query( + ':leave', + animate( + '200ms cubic-bezier(0.4, 0.0, 0.2, 1)', + keyframes([style({ opacity: 1 }), style({ opacity: 0 })]) + ), + { optional: true } + ) + ]) ]) ]; diff --git a/projects/ucap-webmessenger-ui/src/lib/components/float-action-button.component.html b/projects/ucap-webmessenger-ui/src/lib/components/float-action-button.component.html new file mode 100644 index 00000000..2d9a2ceb --- /dev/null +++ b/projects/ucap-webmessenger-ui/src/lib/components/float-action-button.component.html @@ -0,0 +1,21 @@ +
+
+ +
+ +
+
diff --git a/projects/ucap-webmessenger-ui/src/lib/components/float-action-button.component.scss b/projects/ucap-webmessenger-ui/src/lib/components/float-action-button.component.scss new file mode 100644 index 00000000..1c54954a --- /dev/null +++ b/projects/ucap-webmessenger-ui/src/lib/components/float-action-button.component.scss @@ -0,0 +1,34 @@ +.fab-container { + position: fixed; + bottom: 15px; + right: 15px; + z-index: 100; + display: flex; + flex-direction: column-reverse; + align-items: center; + + > div { + display: flex; + flex-direction: column-reverse; + align-items: center; + margin-bottom: 5px; + + button { + margin-bottom: 17px; + } + } +} + +.fab-toggler { + float: right; + z-index: 100; +} + +#fab-dismiss { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 99; +} diff --git a/projects/ucap-webmessenger-ui/src/lib/components/float-action-button.component.spec.ts b/projects/ucap-webmessenger-ui/src/lib/components/float-action-button.component.spec.ts new file mode 100644 index 00000000..6f380aa2 --- /dev/null +++ b/projects/ucap-webmessenger-ui/src/lib/components/float-action-button.component.spec.ts @@ -0,0 +1,27 @@ +/* tslint:disable:no-unused-variable */ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { DebugElement } from '@angular/core'; + +import { FloatActionButtonComponent } from './float-action-button.component'; + +describe('FloatActionButtonComponent', () => { + let component: FloatActionButtonComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [FloatActionButtonComponent] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(FloatActionButtonComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/ucap-webmessenger-ui/src/lib/components/float-action-button.component.ts b/projects/ucap-webmessenger-ui/src/lib/components/float-action-button.component.ts new file mode 100644 index 00000000..dcddea75 --- /dev/null +++ b/projects/ucap-webmessenger-ui/src/lib/components/float-action-button.component.ts @@ -0,0 +1,48 @@ +import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; +import { ucapAnimations } from '@ucap-webmessenger/ui'; + +export interface FloatActionButton { + /** Meterial Icon type */ + icon: string; + divisionType?: string; +} + +@Component({ + selector: 'ucap-ui-float-action-button', + templateUrl: './float-action-button.component.html', + styleUrls: ['./float-action-button.component.scss'], + animations: ucapAnimations +}) +export class FloatActionButtonComponent implements OnInit { + @Input() + fabButtons: FloatActionButton[] = []; + buttons = []; + fabTogglerState = 'inactive'; + + @Output() + buttonClick = new EventEmitter<{ + btn: FloatActionButton; + }>(); + + constructor() {} + ngOnInit() {} + + showItems() { + this.fabTogglerState = 'active'; + this.buttons = this.fabButtons; + } + + hideItems() { + this.fabTogglerState = 'inactive'; + this.buttons = []; + } + + onToggleFab() { + this.buttons.length ? this.hideItems() : this.showItems(); + } + + onClickButton(btn: FloatActionButton) { + this.hideItems(); + this.buttonClick.emit({ btn }); + } +} diff --git a/projects/ucap-webmessenger-ui/src/lib/components/index.ts b/projects/ucap-webmessenger-ui/src/lib/components/index.ts new file mode 100644 index 00000000..b6169f49 --- /dev/null +++ b/projects/ucap-webmessenger-ui/src/lib/components/index.ts @@ -0,0 +1,7 @@ +import { FileUploadQueueComponent } from './file-upload-queue.component'; +import { FloatActionButtonComponent } from './float-action-button.component'; + +export const UI_COMMON_COMPONENTS = [ + FileUploadQueueComponent, + FloatActionButtonComponent +]; diff --git a/projects/ucap-webmessenger-ui/src/lib/ucap-ui.module.ts b/projects/ucap-webmessenger-ui/src/lib/ucap-ui.module.ts index ece8bd9b..bae52d48 100644 --- a/projects/ucap-webmessenger-ui/src/lib/ucap-ui.module.ts +++ b/projects/ucap-webmessenger-ui/src/lib/ucap-ui.module.ts @@ -12,7 +12,7 @@ import { MatSnackBarModule } from '@angular/material/snack-bar'; import { DragDropModule } from '@angular/cdk/drag-drop'; -import { FileUploadQueueComponent } from './components/file-upload-queue.component'; +import { UI_COMMON_COMPONENTS } from './components/index'; import { BottomSheetService } from './services/bottom-sheet.service'; import { ClipboardService } from './services/clipboard.service'; @@ -30,7 +30,7 @@ import { BytesPipe } from './pipes/bytes.pipe'; import { LinefeedToHtmlPipe, HtmlToLinefeedPipe } from './pipes/linefeed.pipe'; import { DateToStringForChatRoomListPipe } from './pipes/dates.pipe'; -const COMPONENTS = [FileUploadQueueComponent]; +const COMPONENTS = [...UI_COMMON_COMPONENTS]; const DIALOGS = [AlertDialogComponent, ConfirmDialogComponent]; const DIRECTIVES = [ ClickOutsideDirective,