Skip to content

Commit

Permalink
feat: create a related prompt component
Browse files Browse the repository at this point in the history
  • Loading branch information
lauramargar committed Dec 17, 2024
1 parent 29e0c2c commit b865f6b
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 121 deletions.
Original file line number Diff line number Diff line change
@@ -1,60 +1,45 @@
<template>
<div class="x-related-prompt" data-test="related-prompt">
<div class="x-related-prompt__info">
<slot name="header" :suggestionText="relatedPrompt.suggestionText">
{{ relatedPrompt.suggestionText }}
</slot>
<slot name="next-queries" :nextQueries="relatedPrompt.nextQueries">
<SlidingPanel :resetOnContentChange="false">
<div class="x-related-prompt__sliding-panel-content">
<button
v-for="(nextQuery, index) in relatedPrompt.nextQueries"
:key="index"
@click="onClick(nextQuery)"
:class="[
'x-button',
{ 'x-selected': selectedNextQuery === nextQuery },
nextQueryButtonClass
]"
>
<slot name="next-query" :nextQuery="nextQuery">
<span>{{ nextQuery }}</span>
<CrossTinyIcon v-if="selectedNextQuery === nextQuery" class="x-icon" />
<PlusIcon v-else class="x-icon" />
</slot>
</button>
</div>
</SlidingPanel>
</slot>
</div>
<div class="x-related-prompt__query-preview">
<slot name="selected-query" :selectedQuery="selectedNextQuery">
{{ selectedNextQuery }}
</slot>
</div>
</div>
<button
@click="toggleSuggestion(index)"
class="x-related-prompt__button"
:class="[{ 'x-related-prompt-selected__button': isSelected(index) }]"
>
<slot name="related-prompt-button-info">
<div class="x-related-prompt__button-info">
<span
class="x-typewritter-initial"
:class="[{ 'x-typewritter-animation': isVisible }]"
:style="{
animationDelay: `${index * 0.4 + 0.05}s`,
'--suggestion-text-length': relatedPrompt.suggestionText.length
}"
>
{{ relatedPrompt.suggestionText }}
</span>
</div>
<CrossTinyIcon v-if="isSelected(index)" class="x-icon-lg" />
<PlusIcon v-else class="x-icon-neutral-80 x-icon-lg" />
</slot>
</button>
</template>
<script lang="ts">
import { defineComponent, PropType, ref } from 'vue';
import { defineComponent, PropType } from 'vue';
import { RelatedPrompt } from '@empathyco/x-types';
import { relatedPromptsXModule } from '../x-module';
import CrossTinyIcon from '../../../components/icons/cross-tiny.vue';
import PlusIcon from '../../../components/icons/plus.vue';
import SlidingPanel from '../../../components/sliding-panel.vue';
import { use$x, useState } from '../../../composables/index';
/**
* This component shows a suggested related prompt with the associated next queries.
* It allows to select one of the next query and show it.
* This component shows a suggested related prompt.
*
* It provide slots to customize the header, the next queries list,
* the individual next query inside the list and the selected query.
* It provides a slot to customize the related prompt button information.
*
* @public
*/
export default defineComponent({
name: 'RelatedPrompt',
components: {
SlidingPanel,
CrossTinyIcon,
PlusIcon
},
Expand All @@ -64,39 +49,31 @@
type: Object as PropType<RelatedPrompt>,
required: true
},
nextQueryButtonClass: {
type: String,
default: 'x-button-outlined'
isVisible: {
type: Boolean,
default: false
},
index: {
type: Number,
required: true
}
},
setup(props) {
const selectedNextQuery = ref(props.relatedPrompt.nextQueries[0]);
setup() {
const x = use$x();
const { selectedPrompt } = useState('relatedPrompts', ['selectedPrompt']);
/**
* Handles the click event on a next query button.
*
* @param nextQuery - The clicked next query.
*/
function onClick(nextQuery: string): void {
if (selectedNextQuery.value === nextQuery) {
selectedNextQuery.value = '';
} else {
selectedNextQuery.value = nextQuery;
}
}
const toggleSuggestion = (index: number): void => {
x.emit('UserSelectedARelatedPrompt', index);
};
return { selectedNextQuery, onClick };
const isSelected = (index: number): boolean => selectedPrompt.value === index;
return {
isSelected,
selectedPrompt,
toggleSuggestion
};
}
});
</script>
<style lang="css" scoped>
.x-related-prompt__info {
display: flex;
flex-direction: column;
}
.x-related-prompt__sliding-panel-content {
display: flex;
gap: 8px;
}
</style>
<style lang="css"></style>
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
</template>
<SlidingPanel
:reset-on-content-change="true"
:button-class="buttonClass"
:scroll-container-class="
selectedPrompt === -1 ? 'desktop:x-sliding-panel-fade desktop:x-sliding-panel-fade-sm' : ''
"
Expand All @@ -13,50 +14,32 @@
<slot name="sliding-panel-left-button" />
</template>

<div
ref="slidingPanelContent"
class="x-related-prompt__sliding-panel-content"
:class="{ 'x-w-[calc(100%)]': selectedPrompt !== -1 }"
>
<slot name="sliding-panel-content">
<div
v-for="(suggestion, index) in relatedPrompts"
:key="index"
:style="{
animationDelay: `${index * 0.4 + 0.05}s`
}"
class="x-related-prompt x-staggered-initial"
:class="[
{ 'x-staggered-animation': isVisible },
{ 'x-hidden': shouldHideButton(index) },
{ 'x-related-prompt-selected': isSelected(index) }
]"
data-test="related-prompt-item"
ref="slidingPanelContent"
class="x-related-prompt__sliding-panel-content"
:class="{ 'x-w-[calc(100%)]': selectedPrompt !== -1 }"
>
<!-- Suggestion -->
<button
@click="toggleSuggestion(index)"
class="x-related-prompt__button"
:class="[{ 'x-related-prompt-selected__button': isSelected(index) }]"
<div
v-for="(suggestion, index) in relatedPrompts"
:key="index"
:style="{
animationDelay: `${index * 0.4 + 0.05}s`
}"
class="x-related-prompt x-staggered-initial"
:class="[
{ 'x-staggered-animation': isVisible },
{ 'x-hidden': shouldHideButton(index) },
{ 'x-related-prompt-selected': isSelected(index) }
]"
data-test="related-prompt-item"
>
<slot name="related-prompt">
<div class="x-related-prompt__button-info">
<span
class="x-typewritter-initial"
:class="[{ 'x-typewritter-animation': isVisible }]"
:style="{
animationDelay: `${index * 0.4 + 0.05}s`,
'--suggestion-text-length': suggestion.suggestionText.length
}"
>
{{ suggestion.suggestionText }}
</span>
</div>
<CrossTinyIcon v-if="isSelected(index)" class="x-icon-lg" />
<PlusIcon v-else class="x-icon-neutral-80 x-icon-lg" />
<slot name="related-prompt-button" v-bind="{ suggestion, index, isVisible }">
<RelatedPrompt :related-prompt="suggestion" :index="index" :is-visible="isVisible" />
</slot>
</button>
</div>
</div>
</div>
</slot>

<template #sliding-panel-right-button>
<slot name="sliding-panel-right-button" />
Expand All @@ -68,15 +51,17 @@
import { defineComponent, onMounted, onUnmounted, ref } from 'vue';
import SlidingPanel from '../../../components/sliding-panel.vue';
import { relatedPromptsXModule } from '../x-module';
import { CrossTinyIcon, PlusIcon } from '../../../components/index';
import { use$x, useState } from '../../../composables/index';
import { useState } from '../../../composables/index';
import RelatedPrompt from './related-prompt.vue';
export default defineComponent({
name: 'RelatedPromptsTagList',
xModule: relatedPromptsXModule.name,
components: { SlidingPanel, PlusIcon, CrossTinyIcon },
components: { RelatedPrompt, SlidingPanel },
props: {
buttonClass: String
},
setup() {
const x = use$x();
const { relatedPrompts, selectedPrompt } = useState('relatedPrompts', [
'relatedPrompts',
'selectedPrompt'
Expand All @@ -97,23 +82,18 @@
observer.disconnect();
});
const toggleSuggestion = (index: number): void => {
x.emit('UserSelectedARelatedPrompt', index);
};
const isSelected = (index: number): boolean => selectedPrompt.value === index;
const shouldHideButton = (index: number): boolean =>
selectedPrompt.value !== -1 && selectedPrompt.value !== index;
return {
isSelected,
isVisible,
shouldHideButton,
isSelected,
relatedPrompts,
selectedPrompt,
shouldHideButton,
slidingPanelContent,
toggleSuggestion
slidingPanelContent
};
}
});
Expand Down

0 comments on commit b865f6b

Please sign in to comment.