From 314dc75c96d32f87e60fe27038452d6383d5807c Mon Sep 17 00:00:00 2001 From: Richard Park Date: Fri, 15 Nov 2019 17:32:48 +0900 Subject: [PATCH] change from expansion panel to tree --- .../left-sidenav/group.component.html | 1 - .../components/expansion-panel.component.html | 140 ++++++--------- .../components/expansion-panel.component.scss | 136 +++++++++------ .../components/expansion-panel.component.ts | 165 +++++++++++++++++- .../src/lib/ucap-ui-group.module.ts | 7 + .../components/user-list-item.component.html | 2 +- .../components/expansion-panel.component.html | 1 + .../components/expansion-panel.component.scss | 4 + .../expansion-panel.component.spec.ts | 27 +++ .../components/expansion-panel.component.ts | 12 ++ .../src/lib/ucap-ui.module.ts | 18 +- 11 files changed, 358 insertions(+), 155 deletions(-) create mode 100644 projects/ucap-webmessenger-ui/src/lib/components/expansion-panel.component.html create mode 100644 projects/ucap-webmessenger-ui/src/lib/components/expansion-panel.component.scss create mode 100644 projects/ucap-webmessenger-ui/src/lib/components/expansion-panel.component.spec.ts create mode 100644 projects/ucap-webmessenger-ui/src/lib/components/expansion-panel.component.ts diff --git a/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-sidenav/group.component.html b/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-sidenav/group.component.html index 88cda4f3..08e4e596 100644 --- a/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-sidenav/group.component.html +++ b/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-sidenav/group.component.html @@ -76,7 +76,6 @@ - + + - - 내 프로필 - - - - - - - - - - - - 즐겨찾기 - ({{ favoritBuddyList.length }}명) - - - - - - - - - - - - -
{{ groupBuddy.group.name }}
- ({{ groupBuddy.buddyList.length }}명) -
- - - - - -
- - - - -
- + + +
  • +
    + + + {{ node?.userInfo?.name }} +
    +
  • +
    + + +
  • +
    + + + + Profile + Favorit + Buddy + +
    +
      +
      +
      + +
      +
    +
  • +
    + + diff --git a/projects/ucap-webmessenger-ui-group/src/lib/components/expansion-panel.component.scss b/projects/ucap-webmessenger-ui-group/src/lib/components/expansion-panel.component.scss index 7a7c496d..35e6c1b0 100644 --- a/projects/ucap-webmessenger-ui-group/src/lib/components/expansion-panel.component.scss +++ b/projects/ucap-webmessenger-ui-group/src/lib/components/expansion-panel.component.scss @@ -1,67 +1,95 @@ @charset 'utf-8'; -:host { - display: flex; - flex: 1; - flex-direction: column; - - .more-spacer { - flex: 1 1 auto; +.group-tree { + padding: 10px; + ul, + li { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; + margin-left: 10px; + } + .group-tree-node-invisible { + display: none; } } -::ng-deep .groupExpansionPanel .mat-expansion-panel-body { - padding: 0; -} -.mat-expansion-panel-header { - padding: 0 20px; - .mat-expansion-panel-header-title { - align-items: center; - font-size: 13px; - } - .mat-expansion-panel-header-description { - margin-right: 0; - } -} - -.mat-icon-button { - margin-right: 0; - width: inherit; -} -.mat-icon { - font-size: 20px; -} -.groupList { - .mat-expansion-panel-header { - padding: 0 20px; - .mat-content { - color: #666666; - overflow: unset; - .panel-title{ - display:inline-flex; - .title-name{ - display:inline-flex; - flex:1 1 auto; - } - .number{ - margin-left:6px; - display: inline-flex; - flex: 0 0 auto; - } +.tree-node-frame { + li { + .path { + .horizontal-line { + display: none; } } } + .mat-tree-node { + min-height: 30px; + font-size: 13px; + padding-left: 20px; + margin-top: 4px; + &:hover { + background-color: #f4f4f4; + border: 1px solid #cccccc; + border-radius: 4px; + box-shadow: 0 1px 4px rgba(32, 33, 36, 0.1); + } + } } -.box-more-spacer { - margin-right: 0; +ul .tree-node-frame li .path > .horizontal-line { + display: inline-block; } -::ng-deep .mat-content{ - overflow: unset !important; +.boxnone { + position: relative; + .vertical-line { + background: rgba(189, 189, 189, 0.4); + bottom: 6px; + display: block; + position: absolute; + top: 0px; + width: 2px; + } + .mat-tree-node:last-child { + padding-bottom: 10px; + } } -.number{ - margin-left:6px; - display: inline-flex; - flex: 0 0 auto; -} \ No newline at end of file +.path { + padding: 6px 4px; + + ul { + li:last-chlid { + border-bottom: 1px solid #dddddd; + } + } + .horizontal-line { + width: 10px; + height: 1px; + background-color: #dddddd; + display: inline-block; + vertical-align: middle; + margin-left: -10px; + } + .mat-icon-button { + padding: 0; + min-width: 0; + width: 20px; + height: 20px; + flex-shrink: 0; + line-height: 20px; + .mat-icon-rtl-mirror { + border: 1px solid #dddddd; + padding: 2px; + font-size: 14px; + min-width: 14px; + min-height: 14px; + line-height: 14px; + width: 20px; + height: 20px; + box-shadow: 0 2px 1px rgba(48, 48, 48, 0.2); + border-radius: 50%; + } + } + .dept-name { + padding-left: 10px; + } +} diff --git a/projects/ucap-webmessenger-ui-group/src/lib/components/expansion-panel.component.ts b/projects/ucap-webmessenger-ui-group/src/lib/components/expansion-panel.component.ts index f9ee4604..88cbaf4c 100644 --- a/projects/ucap-webmessenger-ui-group/src/lib/components/expansion-panel.component.ts +++ b/projects/ucap-webmessenger-ui-group/src/lib/components/expansion-panel.component.ts @@ -6,13 +6,15 @@ import { EventEmitter, ViewChild, ContentChild, - TemplateRef + TemplateRef, + AfterViewInit, + ChangeDetectorRef } from '@angular/core'; import { ucapAnimations } from '@ucap-webmessenger/ui'; import { GroupDetailData, UserInfo } from '@ucap-webmessenger/protocol-sync'; -import { MatAccordion } from '@angular/material'; +import { MatAccordion, MatTreeFlattener } from '@angular/material'; import { ExpansionPanelItemDirective } from '../directives/expansion-panel-item.directive'; import { UserInfoSS, @@ -20,6 +22,31 @@ import { UserInfoDN } from '@ucap-webmessenger/protocol-query'; import { NGXLogger } from 'ngx-logger'; +import { VirtualScrollTreeFlatDataSource } from '@ucap-webmessenger/ui'; +import { FlatTreeControl } from '@angular/cdk/tree'; +import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling'; + +enum NodeType { + None = 'None', + Favorit = 'Favorit', + Profile = 'Profile', + Buddy = 'Buddy' +} + +interface GroupNode { + nodeType: NodeType; + userInfo?: UserInfo; + groupDetail?: GroupDetailData; + children?: GroupNode[]; +} + +interface FlatNode { + expandable: boolean; + level: number; + nodeType: NodeType; + userInfo?: UserInfo; + groupDetail?: GroupDetailData; +} @Component({ selector: 'ucap-group-expansion-panel', @@ -27,15 +54,80 @@ import { NGXLogger } from 'ngx-logger'; styleUrls: ['./expansion-panel.component.scss'], animations: ucapAnimations }) -export class ExpansionPanelComponent implements OnInit { +export class ExpansionPanelComponent implements OnInit, AfterViewInit { @Input() - groupBuddyList: { group: GroupDetailData; buddyList: UserInfo[] }[]; + set myProfileInfo(userInfo: UserInfo) { + if (!userInfo) { + return; + } + const groupNode: GroupNode = { + nodeType: NodeType.Profile, + children: [] + }; + + groupNode.children.push({ + nodeType: NodeType.Profile, + userInfo + }); + + this.profileNodes = [groupNode]; + + this.refreshRootNodeList(); + } + @Input() - favoritBuddyList?: UserInfo[]; + set favoritBuddyList(userInfoList: UserInfo[]) { + if (!userInfoList) { + return; + } + const groupNode: GroupNode = { + nodeType: NodeType.Favorit, + children: [] + }; + + userInfoList.forEach(userInfo => { + groupNode.children.push({ + nodeType: NodeType.Favorit, + userInfo + }); + }); + + this.favoritNodes = [groupNode]; + this.refreshRootNodeList(); + } + @Input() - myProfileInfo?: UserInfo; + set groupBuddyList( + list: { group: GroupDetailData; buddyList: UserInfo[] }[] + ) { + if (!list || 0 === list.length) { + return; + } + + this.buddyNodes = []; + + for (const item of list) { + const groupNode: GroupNode = { + nodeType: NodeType.Buddy, + groupDetail: item.group, + children: [] + }; + + item.buddyList.forEach(userInfo => { + groupNode.children.push({ + nodeType: NodeType.Buddy, + userInfo + }); + }); + + this.buddyNodes.push(groupNode); + } + this.refreshRootNodeList(); + } + @Input() checkable = false; + @Input() /** 선택된 사용자의 리스트 */ selectedUserList?: (UserInfo | UserInfoSS | UserInfoF | UserInfoDN)[] = []; @@ -54,16 +146,64 @@ export class ExpansionPanelComponent implements OnInit { @ContentChild(ExpansionPanelItemDirective, { read: TemplateRef, - static: true + static: false }) expansionPanelItemTemplateRef: TemplateRef; @ViewChild('groupAccordion', { static: true }) groupAccordion: MatAccordion; - constructor(private logger: NGXLogger) {} + @ViewChild('cvsvGroup', { static: false }) + cvsvGroup: CdkVirtualScrollViewport; + + NodeType = NodeType; + + profileNodes: GroupNode[] = []; + favoritNodes: GroupNode[] = []; + buddyNodes: GroupNode[] = []; + + rootNodeList: GroupNode[] = []; + treeControl: FlatTreeControl; + treeFlattener: MatTreeFlattener; + dataSource: VirtualScrollTreeFlatDataSource; + + constructor( + private changeDetectorRef: ChangeDetectorRef, + private logger: NGXLogger + ) { + this.treeControl = new FlatTreeControl( + node => node.level, + node => node.expandable + ); + + this.treeFlattener = new MatTreeFlattener( + (node: GroupNode, level: number) => { + return { + expandable: !!node.children && node.children.length > 0, + level, + nodeType: node.nodeType, + userInfo: node.userInfo, + groupDetail: node.groupDetail + }; + }, + node => node.level, + node => node.expandable, + node => node.children + ); + + this.dataSource = new VirtualScrollTreeFlatDataSource( + this.treeControl, + this.treeFlattener + ); + } ngOnInit() {} + ngAfterViewInit(): void { + this.dataSource.cdkVirtualScrollViewport = this.cvsvGroup; + } + + hasChild = (_: number, node: FlatNode) => node.expandable; + expandMore() { this.groupAccordion.openAll(); } @@ -110,4 +250,13 @@ export class ExpansionPanelComponent implements OnInit { } return false; } + + private refreshRootNodeList(): void { + this.rootNodeList = [ + ...this.profileNodes, + ...this.favoritNodes, + ...this.buddyNodes + ]; + this.dataSource.data = this.rootNodeList; + } } diff --git a/projects/ucap-webmessenger-ui-group/src/lib/ucap-ui-group.module.ts b/projects/ucap-webmessenger-ui-group/src/lib/ucap-ui-group.module.ts index 6bf67ca1..9a1c841a 100644 --- a/projects/ucap-webmessenger-ui-group/src/lib/ucap-ui-group.module.ts +++ b/projects/ucap-webmessenger-ui-group/src/lib/ucap-ui-group.module.ts @@ -4,9 +4,12 @@ import { ReactiveFormsModule } from '@angular/forms'; import { FlexLayoutModule } from '@angular/flex-layout'; +import { ScrollingModule } from '@angular/cdk/scrolling'; + import { MatButtonModule } from '@angular/material/button'; import { MatExpansionModule } from '@angular/material/expansion'; import { MatIconModule } from '@angular/material/icon'; +import { MatTreeModule } from '@angular/material/tree'; import { ExpansionPanelComponent } from './components/expansion-panel.component'; import { ExpansionPanelItemDirective } from './directives/expansion-panel-item.directive'; @@ -22,9 +25,13 @@ const SERVICES = []; CommonModule, ReactiveFormsModule, FlexLayoutModule, + + ScrollingModule, + MatButtonModule, MatExpansionModule, MatIconModule, + MatTreeModule, MatCheckboxModule ], exports: [...COMPONENTS, ...DIRECTIVES], diff --git a/projects/ucap-webmessenger-ui-profile/src/lib/components/user-list-item.component.html b/projects/ucap-webmessenger-ui-profile/src/lib/components/user-list-item.component.html index f3317e38..d86e77b8 100644 --- a/projects/ucap-webmessenger-ui-profile/src/lib/components/user-list-item.component.html +++ b/projects/ucap-webmessenger-ui-profile/src/lib/components/user-list-item.component.html @@ -1,5 +1,5 @@ -
    +
    diff --git a/projects/ucap-webmessenger-ui/src/lib/components/expansion-panel.component.scss b/projects/ucap-webmessenger-ui/src/lib/components/expansion-panel.component.scss new file mode 100644 index 00000000..eae35622 --- /dev/null +++ b/projects/ucap-webmessenger-ui/src/lib/components/expansion-panel.component.scss @@ -0,0 +1,4 @@ +.ucap-expansion-panel-container { + width: 100%; + height: 100%; +} diff --git a/projects/ucap-webmessenger-ui/src/lib/components/expansion-panel.component.spec.ts b/projects/ucap-webmessenger-ui/src/lib/components/expansion-panel.component.spec.ts new file mode 100644 index 00000000..30f18c34 --- /dev/null +++ b/projects/ucap-webmessenger-ui/src/lib/components/expansion-panel.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 { ExpansionPanelComponent } from './expansion-panel.component'; + +describe('ExpansionPanelComponent', () => { + let component: ExpansionPanelComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ExpansionPanelComponent] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ExpansionPanelComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/ucap-webmessenger-ui/src/lib/components/expansion-panel.component.ts b/projects/ucap-webmessenger-ui/src/lib/components/expansion-panel.component.ts new file mode 100644 index 00000000..40959187 --- /dev/null +++ b/projects/ucap-webmessenger-ui/src/lib/components/expansion-panel.component.ts @@ -0,0 +1,12 @@ +import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; + +@Component({ + selector: 'ucap-expansion-panel', + templateUrl: './expansion-panel.component.html', + styleUrls: ['./expansion-panel.component.scss'] +}) +export class ExpansionPanelComponent implements OnInit { + constructor() {} + + ngOnInit() {} +} 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 e536581a..faff4a6c 100644 --- a/projects/ucap-webmessenger-ui/src/lib/ucap-ui.module.ts +++ b/projects/ucap-webmessenger-ui/src/lib/ucap-ui.module.ts @@ -18,6 +18,7 @@ import { DragDropModule } from '@angular/cdk/drag-drop'; import { FileUploadQueueComponent } from './components/file-upload-queue.component'; import { FloatActionButtonComponent } from './components/float-action-button.component'; import { FileViewerComponent } from './components/file-viewer.component'; +import { ExpansionPanelComponent } from './components/expansion-panel.component'; import { BinaryViewerComponent } from './components/file-viewer/binary-viewer.component'; import { DocumentViewerComponent } from './components/file-viewer/document-viewer.component'; @@ -41,7 +42,7 @@ import { BytesPipe } from './pipes/bytes.pipe'; import { LinefeedToHtmlPipe, HtmlToLinefeedPipe } from './pipes/linefeed.pipe'; import { DateToStringForChatRoomListPipe, - DateToStringFormatPipe, + DateToStringFormatPipe } from './pipes/dates.pipe'; import { SecondsToMinutesPipe } from './pipes/seconds-to-minutes.pipe'; @@ -49,18 +50,19 @@ const COMPONENTS = [ FileUploadQueueComponent, FloatActionButtonComponent, FileViewerComponent, + ExpansionPanelComponent, BinaryViewerComponent, DocumentViewerComponent, ImageViewerComponent, SoundViewerComponent, - VideoViewerComponent, + VideoViewerComponent ]; const DIALOGS = [AlertDialogComponent, ConfirmDialogComponent]; const DIRECTIVES = [ ClickOutsideDirective, FileUploadForDirective, - ImageDirective, + ImageDirective ]; const PIPES = [ BytesPipe, @@ -68,13 +70,13 @@ const PIPES = [ HtmlToLinefeedPipe, DateToStringForChatRoomListPipe, DateToStringFormatPipe, - SecondsToMinutesPipe, + SecondsToMinutesPipe ]; const SERVICES = [ BottomSheetService, ClipboardService, DialogService, - SnackBarService, + SnackBarService ]; @NgModule({ @@ -90,17 +92,17 @@ const SERVICES = [ MatSnackBarModule, MatToolbarModule, MatTooltipModule, - DragDropModule, + DragDropModule ], exports: [...COMPONENTS, ...DIRECTIVES, ...PIPES], declarations: [...COMPONENTS, ...DIALOGS, ...DIRECTIVES, ...PIPES], - entryComponents: [...DIALOGS], + entryComponents: [...DIALOGS] }) export class UCapUiModule { public static forRoot(): ModuleWithProviders { return { ngModule: UCapUiModule, - providers: [...SERVICES], + providers: [...SERVICES] }; } }