diff --git a/src/app/playground-components.ts b/src/app/playground-components.ts index 9c4b1d201e..01a70cbe78 100644 --- a/src/app/playground-components.ts +++ b/src/app/playground-components.ts @@ -480,6 +480,12 @@ export const PLAYGROUND_COMPONENTS: ComponentLink[] = [ component: 'ChatCustomMessageComponent', name: 'Chat Custom Message', }, + { + path: 'chat-template-title.component', + link: '/chat/chat-template-title.component', + component: 'ChatTemplateTitleComponent', + name: 'Chat Template Title', + }, ], }, { diff --git a/src/framework/theme/components/chat/chat-title.directive.spec.ts b/src/framework/theme/components/chat/chat-title.directive.spec.ts new file mode 100644 index 0000000000..ada10efcb8 --- /dev/null +++ b/src/framework/theme/components/chat/chat-title.directive.spec.ts @@ -0,0 +1,96 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { Component } from '@angular/core'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { By } from '@angular/platform-browser'; +import { NbThemeModule, NbChatModule, NbChatComponent } from '@nebular/theme'; + +@Component({ + template: ` + + + {{ staticTemplateText }} {{ data.text }} + + + +
+ {{ data.label }} +
+
+ + +
+ `, +}) +export class NbChatTitleTemplateTestComponent { + messages = [ + { + reply: false, + type: 'link', + optionalData: { + href: 'https://akveo.github.io/ngx-admin/', + label: 'Visit Akveo Nebular', + }, + date: new Date(), + user: { + name: 'Frodo Baggins', + avatar: 'https://i.gifer.com/no.gif', + }, + }, + { + text: 'Hello, how are you?', + reply: true, + type: 'text', + date: new Date(), + user: { + name: 'Bilbo Baggins', + avatar: '', + }, + }, + ]; + + title = 'chat title'; + staticTemplateText = 'staticTemplateText'; + contextTemplateText = 'contextTemplateText'; +} + +describe('NbChatTitleDirective', () => { + let fixture: ComponentFixture; + let testComponent: NbChatTitleTemplateTestComponent; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [NoopAnimationsModule, NbThemeModule.forRoot(), NbChatModule], + declarations: [NbChatTitleTemplateTestComponent], + }); + + fixture = TestBed.createComponent(NbChatTitleTemplateTestComponent); + testComponent = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should render title template if provided', () => { + const chatHeaderElement: HTMLElement = fixture.debugElement + .query(By.directive(NbChatComponent)) + .query(By.css('.header')).nativeElement; + const expectedText = ` ${testComponent.staticTemplateText} ${testComponent.contextTemplateText} `; + + expect(chatHeaderElement.textContent).toEqual(expectedText); + }); + + it('should not render text title if template title is provided', () => { + const chatHeaderElement: HTMLElement = fixture.debugElement + .query(By.directive(NbChatComponent)) + .query(By.css('.header')).nativeElement; + + expect(chatHeaderElement.textContent).not.toContain(testComponent.title); + }); +}); diff --git a/src/framework/theme/components/chat/chat-title.directive.ts b/src/framework/theme/components/chat/chat-title.directive.ts new file mode 100644 index 0000000000..5d19673194 --- /dev/null +++ b/src/framework/theme/components/chat/chat-title.directive.ts @@ -0,0 +1,10 @@ +import { Directive, Input, TemplateRef } from '@angular/core'; + +@Directive({ + selector: `[nbChatTitle]`, +}) +export class NbChatTitleDirective { + @Input() context: Object = {}; + + constructor(public templateRef: TemplateRef) {} +} diff --git a/src/framework/theme/components/chat/chat.component.ts b/src/framework/theme/components/chat/chat.component.ts index 4d674c49ba..5eff968a3a 100644 --- a/src/framework/theme/components/chat/chat.component.ts +++ b/src/framework/theme/components/chat/chat.component.ts @@ -26,6 +26,7 @@ import { convertToBoolProperty, NbBooleanInput } from '../helpers'; import { NbChatFormComponent } from './chat-form.component'; import { NbChatMessageComponent } from './chat-message.component'; import { NbChatCustomMessageService } from './chat-custom-message.service'; +import { NbChatTitleDirective } from './chat-title.directive'; /** * Conversational UI collection - a set of components for chat-like UI construction. @@ -101,6 +102,9 @@ import { NbChatCustomMessageService } from './chat-custom-message.service'; * // chat message, available multiple types * ``` * + * You could provide a chat title as a template via the `nbChatTitle` directive. It overrides `title` input. + * @stacked-example(Custom title, chat/chat-template-title.component) + * * Two users conversation showcase: * @stacked-example(Conversation, chat/chat-conversation-showcase.component) * @@ -237,7 +241,18 @@ import { NbChatCustomMessageService } from './chat-custom-message.service'; selector: 'nb-chat', styleUrls: ['./chat.component.scss'], template: ` -
{{ title }}
+
+ + + + {{ title }} + +
+
@@ -283,6 +298,7 @@ export class NbChatComponent implements OnChanges, AfterContentInit, AfterViewIn @ViewChild('scrollable') scrollable: ElementRef; @ContentChildren(NbChatMessageComponent) messages: QueryList; @ContentChild(NbChatFormComponent) chatForm: NbChatFormComponent; + @ContentChild(NbChatTitleDirective) titleTemplate: NbChatTitleDirective; constructor(protected statusService: NbStatusService) {} diff --git a/src/framework/theme/components/chat/chat.module.ts b/src/framework/theme/components/chat/chat.module.ts index cf2c91969b..4aec9a5b5b 100644 --- a/src/framework/theme/components/chat/chat.module.ts +++ b/src/framework/theme/components/chat/chat.module.ts @@ -21,6 +21,7 @@ import { NbChatMessageMapComponent } from './chat-message-map.component'; import { NbChatOptions } from './chat.options'; import { NbChatAvatarComponent } from './chat-avatar.component'; import { NbChatCustomMessageDirective } from './chat-custom-message.directive'; +import { NbChatTitleDirective } from './chat-title.directive'; const NB_CHAT_COMPONENTS = [ NbChatComponent, @@ -33,43 +34,25 @@ const NB_CHAT_COMPONENTS = [ NbChatAvatarComponent, ]; -const NB_CHAT_DIRECTIVES = [ - NbChatCustomMessageDirective, -]; +const NB_CHAT_DIRECTIVES = [NbChatCustomMessageDirective, NbChatTitleDirective]; @NgModule({ - imports: [ - NbSharedModule, - NbIconModule, - NbInputModule, - NbButtonModule, - ], - declarations: [ - ...NB_CHAT_COMPONENTS, - ...NB_CHAT_DIRECTIVES, - ], - exports: [ - ...NB_CHAT_COMPONENTS, - ...NB_CHAT_DIRECTIVES, - ], + imports: [NbSharedModule, NbIconModule, NbInputModule, NbButtonModule], + declarations: [...NB_CHAT_COMPONENTS, ...NB_CHAT_DIRECTIVES], + exports: [...NB_CHAT_COMPONENTS, ...NB_CHAT_DIRECTIVES], }) export class NbChatModule { - static forRoot(options?: NbChatOptions): ModuleWithProviders { return { ngModule: NbChatModule, - providers: [ - { provide: NbChatOptions, useValue: options || {} }, - ], + providers: [{ provide: NbChatOptions, useValue: options || {} }], }; } static forChild(options?: NbChatOptions): ModuleWithProviders { return { ngModule: NbChatModule, - providers: [ - { provide: NbChatOptions, useValue: options || {} }, - ], + providers: [{ provide: NbChatOptions, useValue: options || {} }], }; } } diff --git a/src/framework/theme/public_api.ts b/src/framework/theme/public_api.ts index 5ce429951f..c7565e230b 100644 --- a/src/framework/theme/public_api.ts +++ b/src/framework/theme/public_api.ts @@ -115,6 +115,7 @@ export * from './components/chat/chat.options'; export * from './components/chat/chat-avatar.component'; export * from './components/chat/chat-custom-message.directive'; export * from './components/chat/chat-custom-message.service'; +export * from './components/chat/chat-title.directive'; export * from './components/spinner/spinner.component'; export * from './components/spinner/spinner.directive'; export * from './components/spinner/spinner.module'; diff --git a/src/playground/with-layout/chat/chat-routing.module.ts b/src/playground/with-layout/chat/chat-routing.module.ts index d824e6a760..2fc77dc935 100644 --- a/src/playground/with-layout/chat/chat-routing.module.ts +++ b/src/playground/with-layout/chat/chat-routing.module.ts @@ -5,7 +5,7 @@ */ import { NgModule } from '@angular/core'; -import { RouterModule, Route} from '@angular/router'; +import { RouterModule, Route } from '@angular/router'; import { ChatColorsComponent } from './chat-colors.component'; import { ChatConversationShowcaseComponent } from './chat-conversation-showcase.component'; import { ChatDropComponent } from './chat-drop.component'; @@ -14,6 +14,7 @@ import { ChatShowcaseComponent } from './chat-showcase.component'; import { ChatSizesComponent } from './chat-sizes.component'; import { ChatTestComponent } from './chat-test.component'; import { ChatCustomMessageComponent } from './chat-custom-message.component'; +import { ChatTemplateTitleComponent } from './chat-template-title.component'; const routes: Route[] = [ { @@ -48,10 +49,14 @@ const routes: Route[] = [ path: 'chat-custom-message.component', component: ChatCustomMessageComponent, }, + { + path: 'chat-template-title.component', + component: ChatTemplateTitleComponent, + }, ]; @NgModule({ - imports: [ RouterModule.forChild(routes) ], - exports: [ RouterModule ], + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], }) export class ChatRoutingModule {} diff --git a/src/playground/with-layout/chat/chat-template-title.component.html b/src/playground/with-layout/chat/chat-template-title.component.html new file mode 100644 index 0000000000..3020a1b12f --- /dev/null +++ b/src/playground/with-layout/chat/chat-template-title.component.html @@ -0,0 +1,21 @@ + + +
Chat title content from template. Here is the text provided via context: "{{ data.text }}"
+
+ + + + +
diff --git a/src/playground/with-layout/chat/chat-template-title.component.ts b/src/playground/with-layout/chat/chat-template-title.component.ts new file mode 100644 index 0000000000..f719676b47 --- /dev/null +++ b/src/playground/with-layout/chat/chat-template-title.component.ts @@ -0,0 +1,61 @@ +/** + * @license + * Copyright Akveo. All Rights Reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +import { Component } from '@angular/core'; +import { ChatShowcaseService } from './chat-showcase.service'; + +@Component({ + templateUrl: './chat-template-title.component.html', + providers: [ChatShowcaseService], + styles: [ + ` + ::ng-deep nb-layout-column { + justify-content: center; + display: flex; + } + nb-chat { + width: 500px; + } + `, + ], +}) +export class ChatTemplateTitleComponent { + messages: any[]; + + constructor(protected chatShowcaseService: ChatShowcaseService) { + this.messages = this.chatShowcaseService.loadMessages(); + } + + sendMessage(event: any) { + const files = !event.files + ? [] + : event.files.map((file) => { + return { + url: file.src, + type: file.type, + icon: 'file-text-outline', + }; + }); + + this.messages.push({ + text: event.message, + date: new Date(), + reply: true, + type: files.length ? 'file' : 'text', + files: files, + user: { + name: 'Jonh Doe', + avatar: 'https://i.gifer.com/no.gif', + }, + }); + const botReply = this.chatShowcaseService.reply(event.message); + if (botReply) { + setTimeout(() => { + this.messages.push(botReply); + }, 500); + } + } +} diff --git a/src/playground/with-layout/chat/chat.module.ts b/src/playground/with-layout/chat/chat.module.ts index 7e925108ff..c9f21921e0 100644 --- a/src/playground/with-layout/chat/chat.module.ts +++ b/src/playground/with-layout/chat/chat.module.ts @@ -18,6 +18,7 @@ import { ChatSizesComponent } from './chat-sizes.component'; import { ChatTestComponent } from './chat-test.component'; import { ChatCustomMessageComponent } from './chat-custom-message.component'; import { ChatCustomMessageTableComponent } from './components/chat-custom-message-table.component'; +import { ChatTemplateTitleComponent } from './chat-template-title.component'; @NgModule({ declarations: [ @@ -30,13 +31,8 @@ import { ChatCustomMessageTableComponent } from './components/chat-custom-messag ChatTestComponent, ChatCustomMessageComponent, ChatCustomMessageTableComponent, + ChatTemplateTitleComponent, ], - imports: [ - CommonModule, - NbChatModule.forRoot(), - NbCardModule, - NbButtonModule, - ChatRoutingModule, - ], + imports: [CommonModule, NbChatModule.forRoot(), NbCardModule, NbButtonModule, ChatRoutingModule], }) export class ChatModule {}