-
Notifications
You must be signed in to change notification settings - Fork 19
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(feedback-container): adding feedback-container component #34
Changes from 5 commits
fbd2afc
b2288f2
abbbe26
9e593bd
22d8d42
ee3e21c
69044fc
e08d354
458c7b2
7dfa2e1
958cf1e
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 |
---|---|---|
@@ -0,0 +1,67 @@ | ||
/** | ||
* @license | ||
* | ||
* Copyright IBM Corp. 2023 | ||
* | ||
* This source code is licensed under the Apache-2.0 license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
import '../components/feedback-container/feedback-container'; | ||
import '../components/input-container/input-container'; | ||
import '../components/output-container/output-container'; | ||
|
||
import { html } from 'lit'; | ||
|
||
let hello = 'sajnsjankjnsa'; | ||
let isVisible = false; | ||
setTimeout(() => { | ||
isVisible = true; | ||
}, 3000); | ||
/** | ||
* More on how to set up stories at: https://storybook.js.org/docs/web-components/writing-stories/introduction | ||
*/ | ||
export default { | ||
title: 'Components/Feedback container/Feedback 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. If we put these components in the |
||
tags: ['autodocs'], | ||
}; | ||
|
||
/** | ||
* More on writing stories with args: https://storybook.js.org/docs/web-components/writing-stories/args | ||
* | ||
* @type {{args: {label: string}, render: (function(*): TemplateResult<1>)}} | ||
*/ | ||
export const Default = { | ||
args: { | ||
label: 'Feedback container', | ||
}, | ||
|
||
/** | ||
* Renders the template for Storybook | ||
* @param {object} args Storybook arguments | ||
* @returns {TemplateResult<1>} | ||
*/ | ||
render: (args) => | ||
html` | ||
<c4ai-feedback-container | ||
api-key="some-api-key" | ||
user="[email protected]" | ||
model=""> | ||
<c4ai-output-container> | ||
<p>Hello, How can i help you today</p> | ||
</c4ai-output-container> | ||
<c4ai-input-container> | ||
<p>Hello! how are you?</p> | ||
</c4ai-input-container> | ||
<c4ai-output-container> | ||
<p>I'm just a computer program, but thanks for asking!</p> | ||
</c4ai-output-container> | ||
<c4ai-input-container> | ||
<p>How's weather today outside?</p> | ||
</c4ai-input-container> | ||
<c4ai-output-container> | ||
<p>It's 15.0 degree celcius today</p> | ||
</c4ai-output-container> | ||
</c4ai-feedback-container> | ||
`, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/** | ||
* @license | ||
* | ||
* Copyright IBM Corp. 2023 | ||
* | ||
* This source code is licensed under the Apache-2.0 license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
import '../components/input-container/input-container' | ||
import { html } from 'lit'; | ||
|
||
/** | ||
* More on how to set up stories at: https://storybook.js.org/docs/web-components/writing-stories/introduction | ||
*/ | ||
export default { | ||
title: 'Components/Input container/Input container', | ||
priyanshu891 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
tags: ['autodocs'], | ||
}; | ||
|
||
/** | ||
* More on writing stories with args: https://storybook.js.org/docs/web-components/writing-stories/args | ||
* | ||
* @type {{args: {label: string}, render: (function(*): TemplateResult<1>)}} | ||
*/ | ||
export const Default = { | ||
args: { | ||
label: 'Input container', | ||
}, | ||
|
||
/** | ||
* Renders the template for Storybook | ||
* @param {object} args Storybook arguments | ||
* @returns {TemplateResult<1>} | ||
*/ | ||
render: (args) => | ||
html`<c4ai-input-container content="Hello! This text is inside feedback container"/>` | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
/** | ||
* @license | ||
* | ||
* Copyright IBM Corp. 2023 | ||
* | ||
* This source code is licensed under the Apache-2.0 license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
import { customElement } from 'lit/decorators.js'; | ||
// need to set up package to import global files like the one below. Hardcoding | ||
//the `c4ai`prefixes for now | ||
|
||
// import settings from '../../globals/settings.js'; | ||
import { FeedbackContainer } from './src/feedback-container.template.js'; | ||
|
||
/** | ||
* Component extending the @carbon/web-components' button | ||
*/ | ||
@customElement(`c4ai-feedback-container`) | ||
class C4AIFeedbackContainer extends FeedbackContainer {} | ||
|
||
export default C4AIFeedbackContainer; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,255 @@ | ||
/** | ||
* @license | ||
* | ||
* Copyright IBM Corp. 2023 | ||
* | ||
* This source code is licensed under the Apache-2.0 license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
import { LitElement, html, css } from 'lit'; | ||
import { property, state } from 'lit/decorators.js'; | ||
|
||
import '@carbon/web-components/es/components/textarea/index.js'; | ||
import '@carbon/web-components/es/components/radio-button/index.js'; | ||
import '@carbon/web-components/es/components/button/index.js'; | ||
|
||
export class FeedbackContainer extends LitElement { | ||
static styles = css` | ||
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. can these styles be separated out into its own file? (see extended-button component for example) |
||
.carbon-feedback-wrapper { | ||
position: relative; | ||
} | ||
|
||
.feedback_dialog { | ||
position: absolute; | ||
max-width: 300px; | ||
border: 1px dashed lightcoral; | ||
background: white; | ||
color: black; | ||
padding: 16px; | ||
} | ||
|
||
#selected-text > text-area { | ||
background-color: red; | ||
} | ||
|
||
.bulb-icon { | ||
position: absolute; | ||
} | ||
`; | ||
|
||
@state() | ||
isModelOpen = false; | ||
|
||
@state() | ||
selection; | ||
|
||
@state() | ||
selectedText = ''; | ||
|
||
@state() | ||
range; | ||
|
||
@state() | ||
minOffset = 0; | ||
@state() | ||
maxOffset = 0; | ||
@state() | ||
offset_x = 0; | ||
@state() | ||
offset_y = 0; | ||
|
||
@property({ attribute: 'api-key' }) | ||
private _api_key: string = ''; | ||
|
||
@property({ attribute: 'user' }) | ||
private _user_id: string = ''; | ||
|
||
@property({ attribute: 'ai-model' }) | ||
private _model_id: string = ''; | ||
|
||
get api_key() { | ||
return this._api_key; | ||
} | ||
|
||
get user_id() { | ||
return this._user_id; | ||
} | ||
|
||
get model_id() { | ||
return this._model_id; | ||
} | ||
|
||
@state() | ||
generation_id?: string = ''; | ||
|
||
@state() | ||
app_id?: number; | ||
|
||
static properties = { | ||
formData: { | ||
feedback_content: '', | ||
}, | ||
}; | ||
|
||
constructor() { | ||
super(); | ||
this.formData = { | ||
feedback_content: '', | ||
feedback_value: '', | ||
}; | ||
} | ||
|
||
handleTextArea(event) { | ||
console.log(event?.target.value); | ||
this.formData.feedback_content = event?.target.value; | ||
} | ||
|
||
handleFeedRadio(event) { | ||
console.log(event?.detail.value); | ||
this.formData.feedback_value = event?.detail.value; | ||
} | ||
|
||
handleFormData() { | ||
this.recordFeedback(); | ||
this.selectedText = ''; | ||
this.selection = ''; | ||
this.formData = {}; | ||
this.isModelOpen = false; | ||
} | ||
|
||
|
||
|
||
handleTextSelection() { | ||
this.selection = window.getSelection(); | ||
const fullText = this.selection?.focusNode?.textContent; | ||
const selectedText = this.selection?.toString().trim(); | ||
|
||
if (selectedText) { | ||
this.selectedText = selectedText; | ||
this.setAttribute('selected', ''); | ||
} else { | ||
this.removeAttribute('selected'); | ||
} | ||
|
||
if (this.selectedText) { | ||
this.range = window.getSelection()?.getRangeAt(0).getBoundingClientRect(); | ||
this.minOffset = Math.min( | ||
this.selection.anchorOffset, | ||
this.selection.focusOffset | ||
); | ||
this.maxOffset = Math.max( | ||
this.selection.anchorOffset, | ||
this.selection.focusOffset | ||
); | ||
this.offset_x = this.range?.right + 16; | ||
this.offset_y = this.selection.focusNode.parentElement.offsetTop - 18; | ||
} else { | ||
// this.selection = null | ||
} | ||
} | ||
|
||
// connectedCallback(): void { | ||
// super.connectedCallback(); | ||
// this.addEventListener('click', this.handleTextSelection); | ||
// // document.body.addEventListener('click', this.handleBodyClick.bind(this)) | ||
// // document.onclick = e => this.selection = null | ||
// console.log('Connected'); | ||
// } | ||
|
||
// disconnectedCallback() { | ||
// super.disconnectedCallback(); | ||
// // window.removeEventListener('keydown', this._handleKeydown); | ||
// console.log('Disconnected'); | ||
// } | ||
|
||
openModal() { | ||
this.formData.feedback_content = this.selectedText; | ||
return html` | ||
<div | ||
class="feedback_dialog" | ||
style="top: ${-16}px; left: ${this.range?.left}px"> | ||
<cds-textarea | ||
rows="2" | ||
value=${this.formData.feedback_content} | ||
id="selected-text" | ||
@input=${this.handleTextArea}> | ||
<span slot="label-text">Selected Text:</span> | ||
</cds-textarea> | ||
|
||
<cds-radio-button-group | ||
label-position="right" | ||
orientation="vertical" | ||
name="radio-group" | ||
@cds-radio-button-group-changed=${this.handleFeedRadio} | ||
defaultSelected="harmful"> | ||
<cds-radio-button | ||
value="harmful" | ||
label-text="Harmful"></cds-radio-button> | ||
<cds-radio-button | ||
value="not_harmful" | ||
label-text="Not harmful"></cds-radio-button> | ||
<cds-radio-button | ||
value="something_else" | ||
label-text="Something else"></cds-radio-button> | ||
</cds-radio-button-group> | ||
<cds-button | ||
@click=${this.handleFormData} | ||
size="sm" | ||
style="padding-top:8px" | ||
buttonClassName="save-btn"> | ||
Save | ||
</cds-button> | ||
</div> | ||
`; | ||
} | ||
|
||
bulb() { | ||
return html` | ||
<div | ||
@click=${this.toggle} | ||
class="bulb-icon" | ||
style="top: ${-32}px; left: ${this.range?.left}px"> | ||
<svg | ||
height="24px" | ||
width="24px" | ||
version="1.1" | ||
xmlns="http://www.w3.org/2000/svg" | ||
viewBox="0 0 512 512" | ||
xmlns:xlink="http://www.w3.org/1999/xlink" | ||
enable-background="new 0 0 512 512" | ||
fill="#000000"> | ||
<g id="SVGRepo_bgCarrier" stroke-width="0"></g> | ||
<g | ||
id="SVGRepo_tracerCarrier" | ||
stroke-linecap="round" | ||
stroke-linejoin="round"></g> | ||
<g id="SVGRepo_iconCarrier"> | ||
<g> | ||
<g fill="#e1df93"> | ||
<path | ||
d="m346.1,45.3c-28.7-25.6-67.3-37.8-105.9-33.5-60.7,6.9-110.4,55.7-118.4,116.2-4.7,35.9 4.5,71.4 26.2,99.8 57,74.9 49.5,150.2 49.5,150.2 0,5.8 4.7,10.4 10.4,10.4h96.1c5.8,0 10.4-4.7 10.4-10.4 0,0-9.5-68.7 46.9-146.9 18-25 30-52 30-84.9 5.68434e-14-38.4-16.5-75.2-45.2-100.9zm-1,172.8c-32.1,39.8-50.3,91.2-51.5,148.1h-27.2v-166.4c0-5.8-4.7-10.4-10.4-10.4s-10.4,4.7-10.4,10.4v166.4h-27.2c0-52.3-18.6-104.5-53.7-150.9-18.2-24.1-26.1-54.1-22.1-84.5 6.7-51.1 48.8-92.4 100-98.2 33.2-3.7 65,6.3 89.6,28.3 24.3,21.7 38.3,52.8 38.3,85.4-5.68434e-14,26.5-8.8,51.3-25.4,71.8z"></path> | ||
<path | ||
d="m340.1,416.8h-168.2c-5.8,0-10.4,4.7-10.4,10.4 0,5.8 4.7,10.4 10.4,10.4h11c5.1,35.8 35.9,63.4 73,63.4s68-27.6 73-63.4h11c5.8,0 10.4-4.7 10.4-10.4 0.2-5.8-4.5-10.4-10.2-10.4zm-84.1,63.3c-25.6,0-47.1-18.3-51.9-42.5h103.9c-4.9,24.2-26.4,42.5-52,42.5z"></path> | ||
</g> | ||
</g> | ||
</g> | ||
</svg> | ||
</div> | ||
`; | ||
} | ||
|
||
toggle() { | ||
this.isModelOpen = !this.isModelOpen; | ||
} | ||
|
||
render() { | ||
return html` | ||
<div class="carbon-feedback-wrapper"> | ||
${this.selection ? this.bulb() : ''} | ||
<slot></slot> | ||
${this.isModelOpen ? this.openModal() : ''} | ||
</div> | ||
`; | ||
} | ||
} |
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.
Can these components all be put in the
Chat
package instead?