feat: add ig bubble

This commit is contained in:
Shivam Mishra
2024-12-05 14:20:16 +05:30
parent d610d3e0bb
commit c2021a86d2
3 changed files with 109 additions and 0 deletions
@@ -0,0 +1,46 @@
<script setup>
import Message from './Message.vue';
// import textOnly from './fixtures/textOnly.js';
import instagramConversation from './fixtures/instagramConversation.js';
const messages = instagramConversation;
const shouldGroupWithNext = index => {
if (index === messages.length - 1) return false;
const current = messages[index];
const next = messages[index + 1];
if (next.status === 'failed') return false;
const nextSenderId = next.senderId ?? next.sender?.id;
const currentSenderId = current.senderId ?? current.sender?.id;
if (currentSenderId !== nextSenderId) return false;
// Check if messages are in the same minute by rounding down to nearest minute
return Math.floor(next.createdAt / 60) === Math.floor(current.createdAt / 60);
};
const getReplyToMessage = message => {
const idToCheck = message.contentAttributes.inReplyTo;
if (!idToCheck) return null;
return messages.find(candidate => idToCheck === candidate.id);
};
</script>
<template>
<Story title="Components/Messages/Instagram" :layout="{ type: 'single' }">
<div class="p-4 bg-n-background rounded-lg w-full min-w-5xl grid">
<template v-for="(message, index) in messages" :key="message.id">
<Message
:current-user-id="1"
:group-with-next="shouldGroupWithNext(index)"
:in-reply-to="getReplyToMessage(message)"
v-bind="message"
/>
</template>
</div>
</Story>
</template>
@@ -17,6 +17,7 @@ import ActivityBubble from './bubbles/Activity.vue';
import ImageBubble from './bubbles/Image.vue';
import FileBubble from './bubbles/File.vue';
import AudioBubble from './bubbles/Audio.vue';
import VideoBubble from './bubbles/Video.vue';
import AttachmentsBubble from './bubbles/Attachments.vue';
import EmailBubble from './bubbles/Email/Index.vue';
@@ -242,6 +243,8 @@ const componentToRender = computed(() => {
if (fileType === ATTACHMENT_TYPES.IMAGE) return ImageBubble;
if (fileType === ATTACHMENT_TYPES.FILE) return FileBubble;
if (fileType === ATTACHMENT_TYPES.AUDIO) return AudioBubble;
if (fileType === ATTACHMENT_TYPES.VIDEO) return VideoBubble;
if (fileType === ATTACHMENT_TYPES.IG_REEL) return VideoBubble;
}
if (props.attachments.length > 1 && !props.content) {
@@ -0,0 +1,60 @@
<script setup>
import { computed } from 'vue';
import BaseBubble from './Base.vue';
import Icon from 'next/icon/Icon.vue';
import { ATTACHMENT_TYPES } from '../constants';
/**
* @typedef {Object} Attachment
* @property {number} id - Unique identifier for the attachment
* @property {number} messageId - ID of the associated message
* @property {'image'|'audio'|'video'|'file'|'location'|'fallback'|'share'|'story_mention'|'contact'|'ig_reel'} fileType - Type of the attachment (file or image)
* @property {number} accountId - ID of the associated account
* @property {string|null} extension - File extension
* @property {string} dataUrl - URL to access the full attachment data
* @property {string} thumbUrl - URL to access the thumbnail version
* @property {number} fileSize - Size of the file in bytes
* @property {number|null} width - Width of the image if applicable
* @property {number|null} height - Height of the image if applicable
*/
/**
* @typedef {Object} Props
* @property {Attachment[]} [attachments=[]] - The attachments associated with the message
*/
const props = defineProps({
attachments: {
type: Array,
required: true,
},
});
const attachment = computed(() => {
return props.attachments[0];
});
const isReel = computed(() => {
return attachment.value.fileType === ATTACHMENT_TYPES.IG_REEL;
});
</script>
<template>
<BaseBubble class="overflow-hidden relative group">
<div
v-if="isReel"
class="absolute p-2 flex items-start justify-end size-12 bg-gradient-to-bl from-n-alpha-black1 to-transparent right-0"
>
<Icon icon="i-lucide-instagram" class="text-white" />
</div>
<video
controls
:src="attachment.dataUrl"
:class="{
'max-w-48': isReel,
'max-w-full': !isReel,
}"
@error="hasError = true"
/>
</BaseBubble>
</template>