Skip to content

Commit

Permalink
feat: suggestions component
Browse files Browse the repository at this point in the history
  • Loading branch information
rjborba committed Jul 17, 2024
1 parent baaf623 commit 86e89d5
Show file tree
Hide file tree
Showing 19 changed files with 176 additions and 18 deletions.
19 changes: 19 additions & 0 deletions apps/storybook/stories/orama-chat-suggestion.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { StoryObj, Meta } from '@storybook/web-components'
import type { Components } from 'ui-stencil'
import { fn } from '@storybook/test'

const meta: Meta<Components.OramaChatSuggestions> = {
title: 'Internal/OramaChat',
component: 'orama-chat-suggestions',
}

export default meta

type Story = StoryObj<Components.OramaChatSuggestions>

export const OramaSuggestions: Story = {
args: {
suggestions: ['How to get started?', 'What are the prices?', 'What is Orama?'],
suggestionClicked: fn(),
},
}
2 changes: 1 addition & 1 deletion apps/storybook/stories/orama-facets.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@ export const OramaFacets: Story = {
{ name: 'FacetThree', count: 74 },
],
selectedFacet: 'FacetOne',
onFacetClick: fn(),
facetClicked: fn(),
},
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const OramaButton = /*@__PURE__*/createReactComponent<JSX.OramaButton, HT
export const OramaChat = /*@__PURE__*/createReactComponent<JSX.OramaChat, HTMLOramaChatElement>('orama-chat');
export const OramaChatAssistentMessage = /*@__PURE__*/createReactComponent<JSX.OramaChatAssistentMessage, HTMLOramaChatAssistentMessageElement>('orama-chat-assistent-message');
export const OramaChatMessagesContainer = /*@__PURE__*/createReactComponent<JSX.OramaChatMessagesContainer, HTMLOramaChatMessagesContainerElement>('orama-chat-messages-container');
export const OramaChatSuggestions = /*@__PURE__*/createReactComponent<JSX.OramaChatSuggestions, HTMLOramaChatSuggestionsElement>('orama-chat-suggestions');
export const OramaChatUserMessage = /*@__PURE__*/createReactComponent<JSX.OramaChatUserMessage, HTMLOramaChatUserMessageElement>('orama-chat-user-message');
export const OramaFacets = /*@__PURE__*/createReactComponent<JSX.OramaFacets, HTMLOramaFacetsElement>('orama-facets');
export const OramaInput = /*@__PURE__*/createReactComponent<JSX.OramaInput, HTMLOramaInputElement>('orama-input');
Expand Down
10 changes: 8 additions & 2 deletions packages/ui-stencil-vue/lib/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ export const OramaChatAssistentMessage = /*@__PURE__*/ defineContainer<JSX.Orama
export const OramaChatMessagesContainer = /*@__PURE__*/ defineContainer<JSX.OramaChatMessagesContainer>('orama-chat-messages-container', undefined);


export const OramaChatSuggestions = /*@__PURE__*/ defineContainer<JSX.OramaChatSuggestions>('orama-chat-suggestions', undefined, [
'suggestions',
'suggestionClicked'
]);


export const OramaChatUserMessage = /*@__PURE__*/ defineContainer<JSX.OramaChatUserMessage>('orama-chat-user-message', undefined, [
'message'
]);
Expand All @@ -36,7 +42,7 @@ export const OramaChatUserMessage = /*@__PURE__*/ defineContainer<JSX.OramaChatU
export const OramaFacets = /*@__PURE__*/ defineContainer<JSX.OramaFacets>('orama-facets', undefined, [
'facets',
'selectedFacet',
'onFacetClick'
'facetClicked'
]);


Expand Down Expand Up @@ -68,7 +74,7 @@ export const OramaSearchResults = /*@__PURE__*/ defineContainer<JSX.OramaSearchR
'searchTerm',
'loading',
'error',
'onOramaItemClick'
'oramaItemClick'
]);


Expand Down
25 changes: 21 additions & 4 deletions packages/ui-stencil/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,16 @@ export namespace Components {
}
interface OramaChatMessagesContainer {
}
interface OramaChatSuggestions {
"suggestionClicked": (suggestion: string) => void;
"suggestions": string[];
}
interface OramaChatUserMessage {
"message": TChatMessage;
}
interface OramaFacets {
"facetClicked": (facetName: string) => void;
"facets": Facet[];
"onFacetClick": (facetName: string) => void;
"selectedFacet": string;
}
interface OramaInput {
Expand Down Expand Up @@ -137,6 +141,12 @@ declare global {
prototype: HTMLOramaChatMessagesContainerElement;
new (): HTMLOramaChatMessagesContainerElement;
};
interface HTMLOramaChatSuggestionsElement extends Components.OramaChatSuggestions, HTMLStencilElement {
}
var HTMLOramaChatSuggestionsElement: {
prototype: HTMLOramaChatSuggestionsElement;
new (): HTMLOramaChatSuggestionsElement;
};
interface HTMLOramaChatUserMessageElement extends Components.OramaChatUserMessage, HTMLStencilElement {
}
var HTMLOramaChatUserMessageElement: {
Expand Down Expand Up @@ -185,7 +195,7 @@ declare global {
new (): HTMLOramaSearchElement;
};
interface HTMLOramaSearchResultsElementEventMap {
"onOramaItemClick": SearchResult;
"oramaItemClick": SearchResult;
}
interface HTMLOramaSearchResultsElement extends Components.OramaSearchResults, HTMLStencilElement {
addEventListener<K extends keyof HTMLOramaSearchResultsElementEventMap>(type: K, listener: (this: HTMLOramaSearchResultsElement, ev: OramaSearchResultsCustomEvent<HTMLOramaSearchResultsElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
Expand Down Expand Up @@ -236,6 +246,7 @@ declare global {
"orama-chat": HTMLOramaChatElement;
"orama-chat-assistent-message": HTMLOramaChatAssistentMessageElement;
"orama-chat-messages-container": HTMLOramaChatMessagesContainerElement;
"orama-chat-suggestions": HTMLOramaChatSuggestionsElement;
"orama-chat-user-message": HTMLOramaChatUserMessageElement;
"orama-facets": HTMLOramaFacetsElement;
"orama-input": HTMLOramaInputElement;
Expand Down Expand Up @@ -265,12 +276,16 @@ declare namespace LocalJSX {
}
interface OramaChatMessagesContainer {
}
interface OramaChatSuggestions {
"suggestionClicked"?: (suggestion: string) => void;
"suggestions"?: string[];
}
interface OramaChatUserMessage {
"message"?: TChatMessage;
}
interface OramaFacets {
"facetClicked"?: (facetName: string) => void;
"facets"?: Facet[];
"onFacetClick"?: (facetName: string) => void;
"selectedFacet"?: string;
}
interface OramaInput {
Expand All @@ -293,7 +308,7 @@ declare namespace LocalJSX {
interface OramaSearchResults {
"error"?: boolean;
"loading"?: boolean;
"onOnOramaItemClick"?: (event: OramaSearchResultsCustomEvent<SearchResult>) => void;
"onOramaItemClick"?: (event: OramaSearchResultsCustomEvent<SearchResult>) => void;
"searchTerm"?: SearchResultsProps['searchTerm'];
"sections"?: SearchResultBySection[];
}
Expand Down Expand Up @@ -339,6 +354,7 @@ declare namespace LocalJSX {
"orama-chat": OramaChat;
"orama-chat-assistent-message": OramaChatAssistentMessage;
"orama-chat-messages-container": OramaChatMessagesContainer;
"orama-chat-suggestions": OramaChatSuggestions;
"orama-chat-user-message": OramaChatUserMessage;
"orama-facets": OramaFacets;
"orama-input": OramaInput;
Expand All @@ -361,6 +377,7 @@ declare module "@stencil/core" {
"orama-chat": LocalJSX.OramaChat & JSXBase.HTMLAttributes<HTMLOramaChatElement>;
"orama-chat-assistent-message": LocalJSX.OramaChatAssistentMessage & JSXBase.HTMLAttributes<HTMLOramaChatAssistentMessageElement>;
"orama-chat-messages-container": LocalJSX.OramaChatMessagesContainer & JSXBase.HTMLAttributes<HTMLOramaChatMessagesContainerElement>;
"orama-chat-suggestions": LocalJSX.OramaChatSuggestions & JSXBase.HTMLAttributes<HTMLOramaChatSuggestionsElement>;
"orama-chat-user-message": LocalJSX.OramaChatUserMessage & JSXBase.HTMLAttributes<HTMLOramaChatUserMessageElement>;
"orama-facets": LocalJSX.OramaFacets & JSXBase.HTMLAttributes<HTMLOramaFacetsElement>;
"orama-input": LocalJSX.OramaInput & JSXBase.HTMLAttributes<HTMLOramaInputElement>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

| Property | Attribute | Description | Type | Default |
| --------- | --------- | ----------- | --------------------------------------------------- | ----------- |
| `message` | -- | | `{ role: "user" \| "assistant"; content: string; }` | `undefined` |
| `message` | -- | | `{ role: "assistant" \| "user"; content: string; }` | `undefined` |


## Dependencies
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

| Property | Attribute | Description | Type | Default |
| --------- | --------- | ----------- | --------------------------------------------------- | ----------- |
| `message` | -- | | `{ role: "user" \| "assistant"; content: string; }` | `undefined` |
| `message` | -- | | `{ role: "assistant" \| "user"; content: string; }` | `undefined` |


## Dependencies
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
.suggestions-list {
display: flex;
align-items: center;
column-gap: var(--spacing-s, $spacing-s);
padding: var(--radius-s, $spacing-s) var(--radius-l, $spacing-l);

list-style: none;
margin: 0;
overflow-x: auto;

// TODO: check scroll styles
// Maybe move somewhere else to reuse in some somponents, but not globally
&::-webkit-scrollbar {
height: 0em;
background-color: transparent;
}
}

.suggestion-button {
@include span();
cursor: pointer;

border-radius: var(--radius-l, $radius-l);
border: 1px solid var(--border-color-primary, border-color('primary'));
padding: var(--spacing-m, $spacing-m) var(--spacing-m, $spacing-m);
display: flex;
background-color: var(--background-color-primary, background-color('primary'));
width: max-content;
color: var(--text-color-secondary, text-color('secondary'));

@media (--md-min) {
padding: var(--spacing-xs, $spacing-xs) var(--spacing-m, $spacing-m);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Component, h, Prop } from '@stencil/core'

@Component({
tag: 'orama-chat-suggestions',
styleUrl: 'orama-chat-suggestions.scss',
})
export class OramaChatSuggestions {
@Prop() suggestions: string[]
@Prop() suggestionClicked: (suggestion: string) => void

handleClick(suggestion: string) {
this.suggestionClicked(suggestion)
}

render() {
if (!this.suggestions?.length) {
return null
}

return (
<ul class="suggestions-list">
{this.suggestions.map((suggestion) => {
return (
<li key={suggestion} class="suggestion">
<button type="button" class="suggestion-button" onClick={() => this.handleClick(suggestion)}>
{suggestion}
</button>
</li>
)
})}
</ul>
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# orama-button



<!-- Auto Generated Below -->


## Properties

| Property | Attribute | Description | Type | Default |
| ------------------- | --------- | ----------- | ------------------------------ | ----------- |
| `suggestionClicked` | -- | | `(suggestion: string) => void` | `undefined` |
| `suggestions` | -- | | `string[]` | `undefined` |


## Dependencies

### Used by

- [orama-chat](../orama-chat)

### Graph
```mermaid
graph TD;
orama-chat --> orama-chat-suggestions
style orama-chat-suggestions fill:#f9f,stroke:#333,stroke-width:4px
```

----------------------------------------------

*Built with [StencilJS](https://stenciljs.com/)*
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ orama-chat {

.chat-form-wrapper {
padding: var(--spacing-m, $spacing-m) var(--spacing-l, $spacing-l);
background-color: var(--background-color-tertiary, background-color('tertiary'));
}

.chat-input {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import { chatContext } from '@/context/chatContext'
import '@phosphor-icons/webcomponents/PhPaperPlaneTilt'
import '@phosphor-icons/webcomponents/PhStop'

// TODO: Hardcoding suggestions for now
const SUGGESTIONS = ['How to get started?', 'What are the prices?', 'What is Orama?']

@Component({
tag: 'orama-chat',
styleUrl: 'orama-chat.scss',
Expand All @@ -25,12 +28,21 @@ export class OramaChat {
chatContext.chatService.abortAnswer()
}

handleSuggestionClick = (suggestion: string) => {
chatContext.chatService.sendQuestion(suggestion)
this.inputValue = ''
}

render() {
return (
<Host>
{/* CHAT MESSAGES */}
<div class="messages-container-wrapper">
<orama-chat-messages-container />
{/* TODO: Provide a better animation */}
{!chatContext.messages.length && !chatContext.isLoading ? (
<orama-chat-suggestions suggestions={SUGGESTIONS} suggestionClicked={this.handleSuggestionClick} />
) : null}
<orama-logo-icon />
</div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
### Depends on

- [orama-chat-messages-container](../orama-chat-messages-container)
- [orama-chat-suggestions](../orama-chat-suggestions)
- [orama-logo-icon](../orama-logo-icon)
- [orama-textarea](../orama-textarea)
- [orama-button](../orama-button)
Expand All @@ -23,6 +24,7 @@
```mermaid
graph TD;
orama-chat --> orama-chat-messages-container
orama-chat --> orama-chat-suggestions
orama-chat --> orama-logo-icon
orama-chat --> orama-textarea
orama-chat --> orama-button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ export type Facet = { name: string; count: number }
export class OramaFacets {
@Prop() facets: Facet[]
@Prop() selectedFacet: string
@Prop() onFacetClick: (facetName: string) => void
@Prop() facetClicked: (facetName: string) => void

handleClick(facet: Facet) {
this.onFacetClick(facet.name)
this.facetClicked(facet.name)
}

render() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@

| Property | Attribute | Description | Type | Default |
| --------------- | ---------------- | ----------- | ----------------------------- | ----------- |
| `facetClicked` | -- | | `(facetName: string) => void` | `undefined` |
| `facets` | -- | | `Facet[]` | `undefined` |
| `onFacetClick` | -- | | `(facetName: string) => void` | `undefined` |
| `selectedFacet` | `selected-facet` | | `string` | `undefined` |


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ export type SearchResultsProps = {
})
export class SearchResults {
@Element() el: HTMLUListElement
@Event() onOramaItemClick: EventEmitter<SearchResult>
@Event() oramaItemClick: EventEmitter<SearchResult>
@Prop() sections: SearchResultBySection[] = []
@Prop() searchTerm: SearchResultsProps['searchTerm']
@Prop() loading = false
@Prop() error = false

handleItemClick = (item: SearchResult) => {
if (item?.path) {
this.onOramaItemClick.emit(item)
this.oramaItemClick.emit(item)
window.location.href = item.path
} else {
throw new Error('No path found')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@

## Events

| Event | Description | Type |
| ------------------ | ----------- | -------------------------------------------------------------------------------- |
| `onOramaItemClick` | | `CustomEvent<{ id: string; title: string; description: string; path: string; }>` |
| Event | Description | Type |
| ---------------- | ----------- | -------------------------------------------------------------------------------- |
| `oramaItemClick` | | `CustomEvent<{ id: string; title: string; description: string; path: string; }>` |


## Dependencies
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export class OramaSearch {
<orama-facets
facets={searchState.facets}
selectedFacet={this.selectedFacet}
onFacetClick={this.onFacetClickHandler}
facetClicked={this.onFacetClickHandler}
/>
<orama-search-results
sections={searchState.results}
Expand Down
Loading

0 comments on commit 86e89d5

Please sign in to comment.