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,