Skip to content

Commit 36a7a5e

Browse files
committed
feat(chat): add template for message actions
1 parent df75a6c commit 36a7a5e

File tree

5 files changed

+86
-4
lines changed

5 files changed

+86
-4
lines changed

src/components/chat/chat-message-list.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ import { repeat } from 'lit/directives/repeat.js';
44
import { registerComponent } from '../common/definitions/register.js';
55
import IgcChatMessageComponent from './chat-message.js';
66
import { styles } from './themes/message-list.base.css.js';
7-
import type { AttachmentTemplate, IgcMessage } from './types.js';
7+
import type {
8+
AttachmentTemplate,
9+
IgcMessage,
10+
MessageActionsTemplate,
11+
} from './types.js';
812

913
/**
1014
*
@@ -40,6 +44,9 @@ export default class IgcChatMessageListComponent extends LitElement {
4044
@property({ type: Function })
4145
public attachmentContentTemplate?: AttachmentTemplate;
4246

47+
@property({ type: Function })
48+
public messageActionsTemplate?: MessageActionsTemplate;
49+
4350
private formatDate(date: Date): string {
4451
const today = new Date();
4552
const yesterday = new Date(today);
@@ -121,6 +128,7 @@ export default class IgcChatMessageListComponent extends LitElement {
121128
.attachmentHeaderTemplate=${this.attachmentHeaderTemplate}
122129
.attachmentActionsTemplate=${this.attachmentActionsTemplate}
123130
.attachmentContentTemplate=${this.attachmentContentTemplate}
131+
.messageActionsTemplate=${this.messageActionsTemplate}
124132
></igc-chat-message>
125133
`
126134
)}

src/components/chat/chat-message.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ import { registerComponent } from '../common/definitions/register.js';
55
import { renderMarkdown } from './markdown-util.js';
66
import { IgcMessageAttachmentsComponent } from './message-attachments.js';
77
import { styles } from './themes/message.base.css.js';
8-
import type { AttachmentTemplate, IgcMessage } from './types.js';
8+
import type {
9+
AttachmentTemplate,
10+
IgcMessage,
11+
MessageActionsTemplate,
12+
} from './types.js';
913

1014
/**
1115
*
@@ -45,6 +49,9 @@ export default class IgcChatMessageComponent extends LitElement {
4549
@property({ type: Function })
4650
public attachmentContentTemplate?: AttachmentTemplate;
4751

52+
@property({ type: Function })
53+
public messageActionsTemplate?: MessageActionsTemplate;
54+
4855
protected override render() {
4956
const containerClass = `message-container ${!this.isResponse ? 'sent' : ''}`;
5057

@@ -64,6 +71,9 @@ export default class IgcChatMessageComponent extends LitElement {
6471
>
6572
</igc-message-attachments>`
6673
: ''}
74+
${this.messageActionsTemplate && this.message
75+
? this.messageActionsTemplate(this.message)
76+
: ''}
6777
</div>
6878
</div>
6979
`;

src/components/chat/chat.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import type {
1111
AttachmentTemplate,
1212
IgcMessage,
1313
IgcMessageAttachment,
14+
MessageActionsTemplate,
1415
} from './types.js';
1516

1617
export interface IgcChatComponentEventMap {
@@ -72,6 +73,9 @@ export default class IgcChatComponent extends EventEmitterMixin<
7273
@property({ type: Function })
7374
public attachmentContentTemplate?: AttachmentTemplate;
7475

76+
@property({ type: Function })
77+
public messageActionsTemplate?: MessageActionsTemplate;
78+
7579
public override connectedCallback() {
7680
super.connectedCallback();
7781
this.addEventListener(
@@ -138,6 +142,7 @@ export default class IgcChatComponent extends EventEmitterMixin<
138142
.attachmentHeaderTemplate=${this.attachmentHeaderTemplate}
139143
.attachmentActionsTemplate=${this.attachmentActionsTemplate}
140144
.attachmentContentTemplate=${this.attachmentContentTemplate}
145+
.messageActionsTemplate=${this.messageActionsTemplate}
141146
>
142147
</igc-chat-message-list>
143148
<igc-chat-input

src/components/chat/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,12 @@ export interface IgcMessageAttachment {
1818
size?: number;
1919
thumbnail?: string;
2020
}
21+
2122
export type AttachmentTemplate = (
2223
attachments: IgcMessageAttachment[]
2324
) => TemplateResult;
25+
export type MessageActionsTemplate = (message: IgcMessage) => TemplateResult;
26+
2427
export const attachmentIcon =
2528
'<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M720-330q0 104-73 177T470-80q-104 0-177-73t-73-177v-370q0-75 52.5-127.5T400-880q75 0 127.5 52.5T580-700v350q0 46-32 78t-78 32q-46 0-78-32t-32-78v-370h80v370q0 13 8.5 21.5T470-320q13 0 21.5-8.5T500-350v-350q-1-42-29.5-71T400-800q-42 0-71 29t-29 71v370q-1 71 49 120.5T470-160q70 0 119-49.5T640-330v-390h80v390Z"/></svg>';
2629
export const sendButtonIcon =

stories/chat.stories.ts

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
import type { Meta, StoryObj } from '@storybook/web-components-vite';
22
import { html } from 'lit';
33

4-
import { IgcChatComponent, defineComponents } from 'igniteui-webcomponents';
5-
import type { IgcMessageAttachment } from '../src/components/chat/types.js';
4+
import {
5+
IgcChatComponent,
6+
defineComponents,
7+
registerIconFromText,
8+
} from 'igniteui-webcomponents';
9+
import type {
10+
AttachmentTemplate,
11+
IgcMessageAttachment,
12+
MessageActionsTemplate,
13+
} from '../src/components/chat/types.js';
614

715
defineComponents(IgcChatComponent);
816

@@ -53,6 +61,10 @@ const metadata: Meta<IgcChatComponent> = {
5361
type: 'AttachmentTemplate',
5462
control: 'AttachmentTemplate',
5563
},
64+
messageActionsTemplate: {
65+
type: 'MessageActionsTemplate',
66+
control: 'MessageActionsTemplate',
67+
},
5668
},
5769
args: {
5870
hideAvatar: false,
@@ -75,11 +87,23 @@ interface IgcChatArgs {
7587
attachmentHeaderTemplate: AttachmentTemplate;
7688
attachmentActionsTemplate: AttachmentTemplate;
7789
attachmentContentTemplate: AttachmentTemplate;
90+
messageActionsTemplate: MessageActionsTemplate;
7891
}
7992
type Story = StoryObj<IgcChatArgs>;
8093

8194
// endregion
8295

96+
const thumbUpIcon =
97+
'<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M720-120H280v-520l280-280 50 50q7 7 11.5 19t4.5 23v14l-44 174h258q32 0 56 24t24 56v80q0 7-2 15t-4 15L794-168q-9 20-30 34t-44 14Zm-360-80h360l120-280v-80H480l54-220-174 174v406Zm0-406v406-406Zm-80-34v80H160v360h120v80H80v-520h200Z"/></svg>';
98+
const thumbDownIcon =
99+
'<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M240-840h440v520L400-40l-50-50q-7-7-11.5-19t-4.5-23v-14l44-174H120q-32 0-56-24t-24-56v-80q0-7 2-15t4-15l120-282q9-20 30-34t44-14Zm360 80H240L120-480v80h360l-54 220 174-174v-406Zm0 406v-406 406Zm80 34v-80h120v-360H680v-80h200v520H680Z"/></svg>';
100+
const regenerateIcon =
101+
'<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M480-160q-134 0-227-93t-93-227q0-134 93-227t227-93q69 0 132 28.5T720-690v-110h80v280H520v-80h168q-32-56-87.5-88T480-720q-100 0-170 70t-70 170q0 100 70 170t170 70q77 0 139-44t87-116h84q-28 106-114 173t-196 67Z"/></svg>';
102+
103+
registerIconFromText('thumb_up', thumbUpIcon, 'material');
104+
registerIconFromText('thumb_down', thumbDownIcon, 'material');
105+
registerIconFromText('regenerate', regenerateIcon, 'material');
106+
83107
let messages: any[] = [
84108
{
85109
id: '1',
@@ -89,6 +113,8 @@ let messages: any[] = [
89113
},
90114
];
91115

116+
let isResponseSent = false;
117+
92118
function handleMessageSend(e: CustomEvent) {
93119
const newMessage = e.detail;
94120
messages.push(newMessage);
@@ -121,10 +147,12 @@ function handleMessageSend(e: CustomEvent) {
121147
};
122148
chat.messages = [...messages, emptyResponse];
123149

150+
isResponseSent = false;
124151
setTimeout(() => {
125152
const responseParts = generateAIResponse(e.detail.text).split(' ');
126153
showResponse(chat, responseParts).then(() => {
127154
messages = chat.messages;
155+
isResponseSent = true;
128156
// TODO: add attachments (if any) to the response message
129157
});
130158
}, 1000);
@@ -196,6 +224,34 @@ export const Basic: Story = {
196224
.hideAvatar=${args.hideAvatar}
197225
.hideUserName=${args.hideUserName}
198226
@igcMessageSend=${handleMessageSend}
227+
.messageActionsTemplate=${(msg) =>
228+
msg.isResponse && msg.text.trim()
229+
? isResponseSent
230+
? html`
231+
<div>
232+
<igc-icon-button
233+
name="thumb_up"
234+
collection="material"
235+
variant="flat"
236+
@click=${() => alert(`Liked·message:·${msg.text}`)}
237+
></igc-icon-button>
238+
<igc-icon-button
239+
name="thumb_down"
240+
variant="flat"
241+
collection="material"
242+
@click=${() => alert(`Disliked·message:·${msg.text}`)}
243+
></igc-icon-button>
244+
<igc-icon-button
245+
name="regenerate"
246+
variant="flat"
247+
collection="material"
248+
@click=${() =>
249+
alert(`Response·should·be·re-generated:·${msg.text}`)}
250+
></igc-icon-button>
251+
</div>
252+
`
253+
: ''
254+
: ''}
199255
>
200256
</igc-chat>
201257
`,

0 commit comments

Comments
 (0)