Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(chat): add support for custom message template #2750

Merged
merged 50 commits into from
Jun 15, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
640a815
feat(custom chat messages): added customizable mesages template support
andreipadolin May 24, 2021
58890d9
fix: resolve PR comments
andreipadolin May 26, 2021
d3ef8ff
code refactor
andreipadolin May 28, 2021
fefbb30
updated docs, code refactor
andreipadolin May 31, 2021
91bcfbf
remove unusedfunction
andreipadolin Jun 2, 2021
a48e5bc
style: fix typo
yggg Jun 7, 2021
ed23ee7
docs(chat custom message): simplify code example elements
yggg Jun 7, 2021
7ef1f57
refactor(chat custom message): add property getter
yggg Jun 7, 2021
976e580
refactor(chat custom message): remove return types on lifecycle hooks
yggg Jun 7, 2021
d6f1042
style: add missing semicolon
yggg Jun 7, 2021
edeeb79
refactor: correct spec file name
yggg Jun 7, 2021
6a69fb0
test(chat message): remove usages of non-existent class members
yggg Jun 7, 2021
15edb02
style(chat message): update formatting
yggg Jun 7, 2021
d8702ad
refactor(chat message): add comment on null type check
yggg Jun 7, 2021
7e6c2f9
style(chat message quote): change formatting of input setters
yggg Jun 7, 2021
bc38668
feat(chat custom message, chat avatar) added to public_api theme
andreipadolin Jun 8, 2021
ff0c550
refactor(custom-message-directive): method renaming
andreipadolin Jun 8, 2021
2dabab6
fix(custom-message-showcase): styling
andreipadolin Jun 8, 2021
f7a0f57
refactor(chat-custom-message): updated docs, default styles provided,…
andreipadolin Jun 10, 2021
584ef45
refactor: group chat classes re-export entries together
yggg Jun 10, 2021
22dbe78
refactor(chat-custom-message): move getting custom-message into separ…
andreipadolin Jun 11, 2021
a95beb9
docs(chat-custom-message): update docs
andreipadolin Jun 11, 2021
16f22fb
Merge branch 'master' into feature/custom-chat-message
yggg Jun 15, 2021
50536c2
refactor(custom message directive): group properties with accessors
yggg Jun 15, 2021
6dcb222
docs(custom message directive): rephrase class and members description
yggg Jun 15, 2021
c3fc871
refactor(custom message directive): move type getter declaration to a…
yggg Jun 15, 2021
7cc3234
docs(custom message directive): clarify nbCustomMessageDisableDefault…
yggg Jun 15, 2021
13ce97b
style(custom message service): separate 3rd-party and local imports
yggg Jun 15, 2021
f010fcb
refactor(custom message directive): rename input for disabling styles
yggg Jun 15, 2021
fc0bbd9
docs(custom message directive): add ng-template usage example
yggg Jun 15, 2021
41b5a3b
docs(chat): update custom message section
yggg Jun 15, 2021
4da525a
refactor(chat): inverse boolean expression
yggg Jun 15, 2021
63a4020
refactor(chat): split template literal
yggg Jun 15, 2021
343ec4a
refactor(chat): reduce weight of custom message selectors
yggg Jun 15, 2021
691477c
refactor(chat): remove sender top margin
yggg Jun 15, 2021
133491a
refactor(chat): remove unused property
yggg Jun 15, 2021
953ebfc
refactor(chat): rename method
yggg Jun 15, 2021
637495a
refactor(chat avatar): remove unnecessary div from template
yggg Jun 15, 2021
86320d3
refactor(chat): remove top margins from all paragraphs
yggg Jun 15, 2021
425d3bb
refactor(custom message): simplify default styling
yggg Jun 15, 2021
c413c85
feat(custom message directive): add isReply context property
yggg Jun 15, 2021
3bc5441
style(chat): fix formatting and remove unnecessary changes
yggg Jun 15, 2021
0f60725
docs(custom message service): update description
yggg Jun 15, 2021
1298c8d
fix(custom message): remove double space when no message
yggg Jun 15, 2021
bf88a43
docs(custom message): tidy up the example
yggg Jun 15, 2021
bf14490
docs(custom message directive): reorder usage methods
yggg Jun 15, 2021
ee96691
docs(chat message): add missing word
yggg Jun 15, 2021
aa7debc
refactor(chat message): do not pass type as method parameter
yggg Jun 15, 2021
024c09a
fix(custom message): make container full width when styles disabled
yggg Jun 15, 2021
f082f2d
docs(custom message): add missing article
yggg Jun 15, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
refactor(chat-custom-message): updated docs, default styles provided,…
… code refactor
  • Loading branch information
andreipadolin committed Jun 10, 2021
commit f7a0f579fb9de0ded2e7b90c31244bce99eab7f0
1 change: 1 addition & 0 deletions docs/structure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,7 @@ export const structure = [
'NbChatComponent',
'NbChatMessageComponent',
'NbChatFormComponent',
'NbChatCustomMessageDirective',
],
},
{
Expand Down
32 changes: 32 additions & 0 deletions src/framework/theme/components/chat/_chat.component.theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
font-size: 0.875rem;
color: nb-theme(chat-message-sender-text-color);
margin-bottom: 0.5rem;
margin-top: 0.5rem;
}

p {
Expand Down Expand Up @@ -189,6 +190,14 @@
}
}

.nb-custom-message {
padding: nb-theme(chat-padding);
color: nb-theme(chat-message-sender-text-color);
border-radius: 0.5rem;
display: inline-block;
margin-top: 0.3rem;
}

&.not-reply {
.message {
@include nb-ltr(margin-left, 0.5rem);
Expand All @@ -212,6 +221,19 @@
nb-chat-message-file {
align-items: flex-start;
}

.nb-custom-message {
background: nb-theme(chat-message-background);
color: nb-theme(chat-message-text-color);
border-top-left-radius: 0;
a {
color: nb-theme(chat-message-text-color);
&:hover, &:focus {
text-decoration: none;
color: nb-theme(chat-message-text-color);
}
}
}
}

&.reply {
Expand Down Expand Up @@ -248,7 +270,17 @@
nb-chat-message-file {
align-items: flex-end;
}

.nb-custom-message {
background: nb-theme(chat-message-reply-background-color);
color: nb-theme(chat-message-reply-text-color);
border-top-right-radius: 0;
a:hover, a:focus {
text-decoration: none;
}
}
}

}

nb-chat-form {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Directive, Input, OnDestroy, OnInit, TemplateRef } from '@angular/core';
import { convertToBoolProperty } from '../helpers';
import { NbCustomMessageService } from './custom-message.service';

function throwCustomMessageTypeIsRequired(): void {
Expand All @@ -10,17 +11,24 @@ function throwCustomMessageTypeIsRequired(): void {
* [nbCustomMessage]: should be applied to the ng-template
* or use a structural directive syntax:
*
* ```html
* <div *nbCustomMessage="my-custom-type">
* <!-- custom message -->
* </div>
* ```
*/
@Directive({
selector: `[nbCustomMessage]`,
})
export class NbChatCustomMessageDirective implements OnInit, OnDestroy {
andreipadolin marked this conversation as resolved.
Show resolved Hide resolved

andreipadolin marked this conversation as resolved.
Show resolved Hide resolved
protected _type: string;
protected _useCustomStyling: boolean = false;

/**
* Custom user defined type
* @type {string}
*/
@Input()
get nbCustomMessage(): string {
return this._type;
Expand All @@ -29,20 +37,37 @@ export class NbChatCustomMessageDirective implements OnInit, OnDestroy {
this._type = value;
}

/**
* Flag that allow to disable default styling for custom message container and use user provided styles
*
* ```html
* <div *nbCustomMessage="'custom-name'; disableDefaultStyles: true" class="class-name">
* </div>
* ```html
* @type {boolean}
*/
@Input()
set nbCustomMessageDisableDefaultStyles(val: boolean) {
this._useCustomStyling = convertToBoolProperty(val);
}
get nbCustomMessageDisableDefaultStyles(): boolean {
return this._useCustomStyling;
}

get type(): string {
return this._type
}

constructor(protected templateRef: TemplateRef<any>, protected customMessageService: NbCustomMessageService) { }
constructor(public templateRef: TemplateRef<any>, protected customMessageService: NbCustomMessageService) { }

ngOnInit() {
if (!this._type) {
throwCustomMessageTypeIsRequired();
}
this.customMessageService.registerMessageTemplate(this.type, this.templateRef);
this.customMessageService.register(this.type, this);
}

ngOnDestroy() {
this.customMessageService.unregisterMessageTemplate(this.type);
this.customMessageService.unregister(this.type);
}
}
61 changes: 57 additions & 4 deletions src/framework/theme/components/chat/chat-message.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { animate, state, style, transition, trigger } from '@angular/animations'
import { convertToBoolProperty, NbBooleanInput } from '../helpers';
import { NbChatMessageFile } from './chat-message-file.component';
import { NbCustomMessageService } from './custom-message.service';
import { NbChatCustomMessageDirective } from './chat-custom-message.directive';

/**
* Chat message component.
Expand Down Expand Up @@ -43,6 +44,48 @@ import { NbCustomMessageService } from './custom-message.service';
* </nb-chat-message>
* ```
*
* Custom message.
*
* You can provide a template for you own message types via the ngCustomMessage directive.
* First, you need to provide a message template. To do this write a template of your message in the nb-chat element,
* before nb-chat-message. Mark it's root element with ngCustomMessage directive and define it's type as a value
* of `*ngCustomMessage="my-custom-type"`. Custom messages has simple predefined styles with `.nb-custom-message` class.
* If you want to use custom styling you have to use DisableDefaultStyles input:
* `*nbCustomMessage="'button'; disableDefaultStyles: true" class="your-custom-class"`
*
* ```html
* <div *nbCustomMessage="'link'; let data">
* <a [href]="data.href">{{ data.label }}</a>
* </div>
*
* <div *nbCustomMessage="'img'; disableDefaultStyles: true" class="image-container">
* <picture>
* <img src="https://i.gifer.com/no.gif" alt="picture">
* </picture>
* </div>
* ```
* // Important note
* Than, you need to set type property of the message which should be rendered via you custom template
* to the value you passed to the nbCustomMessage directive.
*
* Example of message object
* ```ts
* {
* reply: false,
* type: 'link',
* customMessageData: {
* 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',
* },
* },
* ```
* @stacked-example(Custom message, chat/chat-custom-message.component)
*
* @styles
*
* chat-message-background:
Expand Down Expand Up @@ -101,7 +144,9 @@ import { NbCustomMessageService } from './custom-message.service';
[dateFormat]="dateFormat"
[message]="message">
</nb-chat-message-text>
<ng-container [ngTemplateOutlet]="_getTemplateByType(type)" [ngTemplateOutletContext]="_getTemplateContext()"></ng-container>
<div [class.nb-custom-message]="!isCustomStylingScheme(type)">
<ng-container [ngTemplateOutlet]="_getTemplateByType(type)" [ngTemplateOutletContext]="_getTemplateContext()"></ng-container>
</div>
</ng-template>
`,
animations: [
Expand All @@ -121,6 +166,7 @@ import { NbCustomMessageService } from './custom-message.service';
export class NbChatMessageComponent {

protected readonly defaultMessageTypes: string[] = ['text', 'file', 'map', 'quote'];
protected customMessageInstance: NbChatCustomMessageDirective;

avatarStyle: SafeStyle;

Expand Down Expand Up @@ -221,10 +267,8 @@ export class NbChatMessageComponent {
getInitials(): string {
if (this.sender) {
const names = this.sender.split(' ');

return names.map(n => n.charAt(0)).splice(0, 2).join('').toUpperCase();
}

return '';
}

Expand All @@ -234,7 +278,7 @@ export class NbChatMessageComponent {
}

_getTemplateByType(type: string): TemplateRef<any> {
const template = this.customMessageService.getMessageTemplate(type);
const template = this.customMessageInstance.templateRef;
if (!template) {
throw new Error(`nb-chat: Can't find template for custom type '${type}'.
Make sure you provide it in the chat component with *nbCustomMessage='${type}'.`);
Expand All @@ -246,4 +290,13 @@ export class NbChatMessageComponent {
return { $implicit: this.customMessageData };
}

isCustomStylingScheme(type): boolean {
this.extractCustomMessageInstance(type);
return this.customMessageInstance.nbCustomMessageDisableDefaultStyles;
}

protected extractCustomMessageInstance(type: string): void {
this.customMessageInstance = this.customMessageService.getInstance(type);
}

}
20 changes: 10 additions & 10 deletions src/framework/theme/components/chat/custom-message.service.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import { Injectable, TemplateRef } from '@angular/core';
import { Injectable } from '@angular/core';
import { NbChatCustomMessageDirective } from './chat-custom-message.directive';

/**
* Service for self register custom templates
* Service for self register custom messages
*/
@Injectable()
export class NbCustomMessageService {

protected readonly customMessages = new Map<string, TemplateRef<any>>();
protected readonly customMessages = new Map<string, NbChatCustomMessageDirective>();

getMessageTemplate(type: string): TemplateRef<any> | undefined {
return this.customMessages.get(type);
}

registerMessageTemplate(type: string, template: TemplateRef<any>): void {
this.customMessages.set(type, template);
register(type: string, instance: NbChatCustomMessageDirective): void {
this.customMessages.set(type, instance);
}

unregisterMessageTemplate(type: string): boolean {
unregister(type: string): boolean {
return this.customMessages.delete(type);
}

getInstance(type: string): NbChatCustomMessageDirective | undefined {
return this.customMessages.get(type);
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
<nb-chat title="Nebular Conversational UI" size="large">
<div *nbCustomMessage="'link'; let data" class="link-wrapper">
<a class="custom-chat-link link-control" [href]="data.href">{{ data.label }}</a>

<div *nbCustomMessage="'link'; let data">
<a [href]="data.href">{{ data.label }}</a>
</div>

<div *nbCustomMessage="'button'; let data" class="button-wrapper">
<div *nbCustomMessage="'button'; let data; disableDefaultStyles: true" class="button-wrapper">
<button nbButton class="custom-button">{{ data }}</button>
</div>

<div *nbCustomMessage="'img'" class="image-container">
<div *nbCustomMessage="'img'; disableDefaultStyles: true" class="image-container">
<picture>
<img src="https://i.gifer.com/no.gif" alt="picture">
</picture>
</div>

<div *nbCustomMessage="'table'; let data" class="table-container">
<div *nbCustomMessage="'table'; let data">
<nb-custom-message-table [tableHeader]="data"></nb-custom-message-table>
</div>

Expand Down
33 changes: 11 additions & 22 deletions src/playground/with-layout/chat/chat-custom-message.component.scss
Original file line number Diff line number Diff line change
@@ -1,35 +1,24 @@
nb-chat {
width: 500px;
andreipadolin marked this conversation as resolved.
Show resolved Hide resolved
margin: 0 auto;
}

.link-wrapper {
padding: 1rem 1rem 1rem 0;

.custom-chat-link {
background: #3366ff;
color: #ffffff;
padding: 1rem;
border-radius: 0.5rem;
border-top-left-radius: 0;
}
}

.table-container {
padding-top: 1rem;
}
img {
max-width: 100%;
max-height: 100%;
}

.image-container {
flex: 1 1 auto;
.table-container {
padding-top: 1rem;
}

img {
max-width: 100%;
max-height: 100%;
}
}
.image-container {
flex: 1 1 auto;
}

.button-wrapper {
padding-top: 5px;
display: inline-block;
}

.custom-button {
Expand Down
Loading