-
Notifications
You must be signed in to change notification settings - Fork 139
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: add custom styling feature #137
Changes from all commits
de065ce
40f2402
57173d5
8d8cca4
45313c2
d879e1f
0a04c2e
3910b3c
78ecd64
0c9111b
b4f9be1
3f2f69f
02e52b8
9cfda4a
0fdd80d
f8680ac
5a79b0c
f86f481
bec7a44
d71cd3f
38f5180
a05cf86
4dfbf74
faa2d5a
a5d39f9
ea25016
4a891ac
d1bab48
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,6 +25,9 @@ import iconSpinner from '../public/svg/spinner-icon.svg?raw'; | |
import iconMicOff from '../public/svg/mic-icon.svg?raw'; | ||
import iconMicOn from '../public/svg/mic-record-on-icon.svg?raw'; | ||
|
||
// Branding | ||
import iconLogo from '../public/branding/brand-logo-contoso.svg?raw'; | ||
|
||
import { marked } from 'marked'; | ||
|
||
/** | ||
|
@@ -56,9 +59,14 @@ export class ChatComponent extends LitElement { | |
@property({ type: String, attribute: 'data-use-stream', converter: (value) => value?.toLowerCase() === 'true' }) | ||
useStream: boolean = chatHttpOptions.stream; | ||
|
||
@property({ type: String, attribute: 'data-custom-branding', converter: (value) => value?.toLowerCase() === 'true' }) | ||
isCustomBranding: boolean = globalConfig.IS_CUSTOM_BRANDING; | ||
|
||
@property({ type: String, attribute: 'data-overrides', converter: (value) => JSON.parse(value || '{}') }) | ||
overrides: RequestOverrides = {}; | ||
|
||
@property({ type: String, attribute: 'data-custom-styles', converter: (value) => JSON.parse(value || '{}') }) | ||
customStyles: any = {}; | ||
//-- | ||
|
||
@property({ type: String }) | ||
|
@@ -133,6 +141,26 @@ export class ChatComponent extends LitElement { | |
|
||
static override styles = [mainStyle]; | ||
|
||
// The following block is only necessary when you want to override the component from settings in the outside. | ||
// Remove this block when not needed, considering that updated() is a LitElement lifecycle method | ||
// that may be used by other components if you update this code. | ||
override updated(changedProperties: Map<string | number | symbol, unknown>) { | ||
super.updated(changedProperties); | ||
|
||
if (changedProperties.has('customStyles')) { | ||
this.style.setProperty('--c-accent-high', this.customStyles.AccentHigh); | ||
this.style.setProperty('--c-accent-light', this.customStyles.AccentLight); | ||
this.style.setProperty('--c-accent-dark', this.customStyles.AccentDark); | ||
this.style.setProperty('--c-text-color', this.customStyles.TextColor); | ||
this.style.setProperty('--c-light-gray', this.customStyles.BackgroundColor); | ||
this.style.setProperty('--c-dark-gray', this.customStyles.ForegroundColor); | ||
this.style.setProperty('--c-base-gray', this.customStyles.FormBackgroundColor); | ||
this.style.setProperty('--radius-base', this.customStyles.BorderRadius); | ||
this.style.setProperty('--border-base', this.customStyles.BorderWidth); | ||
this.style.setProperty('--font-base', this.customStyles.FontBaseSize); | ||
} | ||
} | ||
|
||
// debounce dispatching must-scroll event | ||
debounceScrollIntoView(): void { | ||
let timeout: any = 0; | ||
|
@@ -609,6 +637,33 @@ export class ChatComponent extends LitElement { | |
return this.isProcessingResponse ? cancelChatButton : submitChatButton; | ||
} | ||
|
||
// Render Branding if custom branding is enabled | ||
renderBrandingBanner() { | ||
if (this.isCustomBranding) { | ||
return html` | ||
<header class="branding__banner"> | ||
<a class="branding__link" href="${globalConfig.BRANDING_URL}" target="_blank" rel="noopener noreferrer"> | ||
${unsafeSVG(iconLogo)} | ||
</a> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. reuse this.renderBrandingAvatar |
||
<h1 class="branding__hl">${globalConfig.BRANDING_HEADLINE}</h1> | ||
</header> | ||
`; | ||
} | ||
return ''; | ||
} | ||
|
||
// Render assistant logo as per branding | ||
renderBrandingAvatar() { | ||
if (this.isCustomBranding) { | ||
return html` | ||
<a class="branding__link" href="${globalConfig.BRANDING_URL}" target="_blank" rel="noopener noreferrer"> | ||
${unsafeSVG(iconLogo)} | ||
</a> | ||
`; | ||
} | ||
return ''; | ||
} | ||
|
||
// Render the chat component as a web component | ||
override render() { | ||
return html` | ||
|
@@ -636,32 +691,35 @@ export class ChatComponent extends LitElement { | |
${message.isUserMessage | ||
? '' | ||
: html` <div class="chat__header"> | ||
<button | ||
title="${globalConfig.SHOW_THOUGH_PROCESS_BUTTON_LABEL_TEXT}" | ||
class="button chat__header--button" | ||
data-testid="chat-show-thought-process" | ||
@click="${this.handleShowThoughtProcess}" | ||
?disabled="${this.isShowingThoughtProcess || !this.canShowThoughtProcess}" | ||
> | ||
<span class="chat__header--span" | ||
>${globalConfig.SHOW_THOUGH_PROCESS_BUTTON_LABEL_TEXT}</span | ||
<div class="chat__header--avatar">${this.renderBrandingAvatar()}</div> | ||
<div class="chat__header--buttons"> | ||
<button | ||
title="${globalConfig.SHOW_THOUGH_PROCESS_BUTTON_LABEL_TEXT}" | ||
class="button chat__header--button" | ||
data-testid="chat-show-thought-process" | ||
@click="${this.handleShowThoughtProcess}" | ||
?disabled="${this.isShowingThoughtProcess || !this.canShowThoughtProcess}" | ||
> | ||
|
||
${unsafeSVG(iconLightBulb)} | ||
</button> | ||
<button | ||
title="${globalConfig.COPY_RESPONSE_BUTTON_LABEL_TEXT}" | ||
class="button chat__header--button" | ||
@click="${this.copyResponseToClipboard}" | ||
?disabled="${this.isDisabled}" | ||
> | ||
<span class="chat__header--span" | ||
>${this.isResponseCopied | ||
? globalConfig.COPIED_SUCCESSFULLY_MESSAGE | ||
: globalConfig.COPY_RESPONSE_BUTTON_LABEL_TEXT}</span | ||
<span class="chat__header--span" | ||
>${globalConfig.SHOW_THOUGH_PROCESS_BUTTON_LABEL_TEXT}</span | ||
> | ||
|
||
${unsafeSVG(iconLightBulb)} | ||
</button> | ||
<button | ||
title="${globalConfig.COPY_RESPONSE_BUTTON_LABEL_TEXT}" | ||
class="button chat__header--button" | ||
@click="${this.copyResponseToClipboard}" | ||
?disabled="${this.isDisabled}" | ||
> | ||
${this.isResponseCopied ? unsafeSVG(iconSuccess) : unsafeSVG(iconCopyToClipboard)} | ||
</button> | ||
<span class="chat__header--span" | ||
>${this.isResponseCopied | ||
? globalConfig.COPIED_SUCCESSFULLY_MESSAGE | ||
: globalConfig.COPY_RESPONSE_BUTTON_LABEL_TEXT}</span | ||
> | ||
${this.isResponseCopied ? unsafeSVG(iconSuccess) : unsafeSVG(iconCopyToClipboard)} | ||
</button> | ||
</div> | ||
</div>`} | ||
${message.text.map((textEntry) => this.renderTextEntry(textEntry))} | ||
${this.renderCitation(message.citations)} | ||
|
@@ -694,7 +752,8 @@ export class ChatComponent extends LitElement { | |
<!-- Conditionally render default prompts based on hasDefaultPromptsEnabled --> | ||
${this.hasDefaultPromptsEnabled | ||
? html` | ||
<div class="defaults__container"> | ||
${this.renderBrandingBanner()} | ||
<div class="defaults__container" data-testid="chat-branding"> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this should probably be on the branding header and not the default container. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I created a rendering function, so I'm not sure exactly what you mean here. But let's put it in the back burner to review when we have all merged in. |
||
<h1 class="headline"> | ||
${this.interactionModel === 'chat' | ||
? this.title || globalConfig.DEFAULT_PROMPTS_HEADING_CHAT | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
check out and see if styleMap directive for lit would be useful here. https://lit.dev/docs/components/styles/#dynamic-classes-and-styles