feat: add message container
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import TextBubble from './bubbles/Text.vue';
|
||||
import Avatar from 'next/avatar/Avatar.vue';
|
||||
import Icon from 'next/icon/Icon.vue';
|
||||
|
||||
const props = defineProps({
|
||||
variant: {
|
||||
type: String,
|
||||
required: true,
|
||||
validator: value => ['user', 'agent', 'system', 'private'].includes(value),
|
||||
},
|
||||
orientation: {
|
||||
type: String,
|
||||
default: 'left',
|
||||
validator: value => ['left', 'right', 'center'].includes(value),
|
||||
},
|
||||
text: {
|
||||
type: String,
|
||||
default: 'Hello World',
|
||||
},
|
||||
user: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
|
||||
const flexOrientationClass = computed(() => {
|
||||
const map = {
|
||||
left: 'justify-start',
|
||||
right: 'justify-end',
|
||||
center: 'justify-center',
|
||||
};
|
||||
|
||||
return map[props.orientation];
|
||||
});
|
||||
|
||||
const gridClass = computed(() => {
|
||||
const map = {
|
||||
left: 'grid grid-cols-[24px_1fr]',
|
||||
right: 'grid grid-cols-[1fr_24px]',
|
||||
};
|
||||
|
||||
return map[props.orientation];
|
||||
});
|
||||
|
||||
const gridTemplate = computed(() => {
|
||||
const map = {
|
||||
left: `
|
||||
"avatar bubble"
|
||||
"spacer meta"
|
||||
`,
|
||||
right: `
|
||||
"bubble avatar"
|
||||
"meta spacer"
|
||||
`,
|
||||
};
|
||||
|
||||
return map[props.orientation];
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex w-full" :class="flexOrientationClass">
|
||||
<div v-if="variant === 'system'">
|
||||
<TextBubble v-bind="props" />
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
:class="gridClass"
|
||||
class="gap-x-3 gap-y-2 grid-area"
|
||||
:style="{
|
||||
gridTemplateAreas: gridTemplate,
|
||||
gridTemplateColumns:
|
||||
props.orientation === 'center' ? '1fr' : 'auto 1fr',
|
||||
}"
|
||||
>
|
||||
<div class="[grid-area:avatar] flex items-end">
|
||||
<Avatar :name="user" src="" size="24" />
|
||||
</div>
|
||||
<TextBubble v-bind="props" class="[grid-area:bubble]" />
|
||||
<div
|
||||
class="[grid-area:meta] text-xs text-n-slate-11 flex items-center gap-1.5"
|
||||
:class="flexOrientationClass"
|
||||
>
|
||||
<span>{{ user }} {{ '• 1m ago' }}</span>
|
||||
<Icon
|
||||
v-if="variant === 'private'"
|
||||
icon="i-lucide-lock-keyhole"
|
||||
class="text-n-slate-10 size-3"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
+14
-2
@@ -1,7 +1,13 @@
|
||||
<script setup>
|
||||
import MessageBubble from './MessageBubble.vue';
|
||||
import Message from './Message.vue';
|
||||
|
||||
const messages = [
|
||||
{
|
||||
variant: 'user',
|
||||
user: 'Elizabeth',
|
||||
text: 'Hey, the usual things I order is out of stock.',
|
||||
orientation: 'left',
|
||||
},
|
||||
{
|
||||
variant: 'system',
|
||||
text: 'Conversation auto-assigned to Stanley',
|
||||
@@ -9,31 +15,37 @@ const messages = [
|
||||
},
|
||||
{
|
||||
variant: 'agent',
|
||||
user: 'Stanley',
|
||||
text: 'Hello Elizabeth, there was a recent change in our office supplies.',
|
||||
orientation: 'right',
|
||||
},
|
||||
{
|
||||
variant: 'private',
|
||||
user: 'Stanley',
|
||||
text: 'Should we give her a premium discount?',
|
||||
orientation: 'right',
|
||||
},
|
||||
{
|
||||
variant: 'private',
|
||||
user: 'Jim',
|
||||
text: 'They have placed multiple orders already, can go ahead. @Michael thoughts?',
|
||||
orientation: 'left',
|
||||
},
|
||||
{
|
||||
variant: 'private',
|
||||
user: 'Michael',
|
||||
text: 'Yes, let’s offer her a 20% discount',
|
||||
orientation: 'left',
|
||||
},
|
||||
{
|
||||
variant: 'agent',
|
||||
user: 'Stanley',
|
||||
text: 'If you want to buy our premium supplies, we can offer you a 20% discount! They come with indices and laser beams! ⚡',
|
||||
orientation: 'right',
|
||||
},
|
||||
{
|
||||
variant: 'user',
|
||||
user: 'Elizabeth',
|
||||
text: 'That’s great!',
|
||||
orientation: 'left',
|
||||
},
|
||||
@@ -46,7 +58,7 @@ const messages = [
|
||||
:layout="{ type: 'grid', width: '800' }"
|
||||
>
|
||||
<div class="p-4 bg-n-background rounded-lg w-full min-w-5xl grid gap-4">
|
||||
<MessageBubble v-for="message in messages" v-bind="message" />
|
||||
<Message v-for="message in messages" v-bind="message" />
|
||||
</div>
|
||||
</Story>
|
||||
</template>
|
||||
+2
-14
@@ -29,16 +29,6 @@ const orientationMap = {
|
||||
right: 'rounded-xl rounded-br-sm',
|
||||
};
|
||||
|
||||
const containetFlexJustify = computed(() => {
|
||||
const map = {
|
||||
left: 'justify-start',
|
||||
right: 'justify-end',
|
||||
center: 'justify-center',
|
||||
};
|
||||
|
||||
return map[props.orientation];
|
||||
});
|
||||
|
||||
const messageClass = computed(() => {
|
||||
const classToApply = [varaintBaseMap[props.variant]];
|
||||
|
||||
@@ -53,9 +43,7 @@ const messageClass = computed(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex w-full" :class="containetFlexJustify">
|
||||
<div class="max-w-md text-sm" :class="messageClass">
|
||||
{{ text }}
|
||||
</div>
|
||||
<div class="max-w-md text-sm" :class="messageClass">
|
||||
{{ text }}
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user