primevue-mirror/apps/showcase/components/landing/samples/ChatApp.vue

434 lines
23 KiB
Vue
Raw Normal View History

2024-06-11 21:33:37 +00:00
<template>
<div class="flex-1 h-full overflow-y-auto overflow-x-clip overflow-hidden flex border border-surface rounded-2xl">
<div class="w-4/12 xl:w-3/12 min-w-40 overflow-auto flex flex-col gap-6">
<div class="flex flex-col gap-6 pt-3 pb-2 -mb-2 px-5 sticky top-0 bg-surface-0 dark:bg-surface-950 z-10">
<div class="flex items-center justify-between gap-6 text-color">
<div class="text-2xl font-medium lead">Chats</div>
<Button icon="pi pi-plus" text />
</div>
</div>
<div class="px-5">
<IconField iconPosition="left">
<InputIcon class="pi pi-search"> </InputIcon>
<InputText v-model="search" placeholder="Search" class="w-full" />
</IconField>
</div>
<div class="w-full px-5">
<SelectButton
v-model="value"
:options="options"
aria-labelledby="basic"
:pt="{
root: {
class: 'w-full'
},
pcbutton: {
root: {
class: 'flex-1'
}
}
}"
/>
</div>
<div class="flex-1 flex flex-col">
<div
v-for="chat in chats"
:key="chat.name"
class="flex items-center gap-2 p-4 cursor-pointer hover:bg-emphasis transition-all"
:class="{
'bg-emphasis': chat.name === activeChat
}"
>
<div class="relative">
<div v-if="chat.active !== undefined" class="absolute top-0 right-0 p-[1px] bg-surface-0 dark:bg-surface-950 rounded-full flex items-center justify-center">
<Badge :severity="chat.active ? 'success' : 'danger'" class="p-1.5"></Badge>
</div>
<Avatar
v-bind="chat.image ? { image: chat.image } : { label: chat.capName }"
:class="{
'bg-violet-100 text-violet-950': !chat.image
}"
class="text-base font-medium flex"
size="large"
shape="circle"
/>
</div>
<div class="flex-1">
<div class="flex items-start gap-1 justify-between">
<div class="text-color font-medium leading-6">{{ chat.name }}</div>
<div class="text-sm text-muted-color leading-5">{{ chat.time }}</div>
</div>
<div class="flex items-center gap-5 justify-between mt-1">
<div class="text-muted-color text-sm leading-5 line-clamp-1">{{ chat.lastMessage }}</div>
<Badge v-if="chat.unreadMessageCount > 0" :value="chat.unreadMessageCount" severity="contrast"></Badge>
</div>
</div>
</div>
</div>
</div>
<div class="w-8/12 xl:w-6/12 border-x border-surface flex flex-col">
<div class="flex items-center p-4 gap-7 border-b border-surface">
<div class="flex items-center">
<Avatar image="https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar-primetek.png" class="mr-2 av" size="large" shape="circle" />
<div class="flex-1">
<div class="text-color leading-6 cursor-pointer hover:text-muted-color-emphasis transition-colors">PrimeTek</div>
<div class="text-muted-color leading-5 line-clamp-1 mt-1">Cody Fisher, Esther Howard, Jerome Bell, Kristin Watson, Ronald Richards, Darrell Steward</div>
</div>
</div>
<div class="flex items-center gap-2">
<Button icon="pi pi-phone" text />
<Button icon="pi pi-search" text />
<Button type="button" icon="pi pi-ellipsis-h" text @click="toggle" aria-haspopup="true" aria-controls="overlay_menu" />
<Menu ref="menu" id="overlay_menu" :model="menuItems" :popup="true" />
</div>
</div>
<div class="flex-1 overflow-y-auto flex flex-col gap-8 py-8 px-6">
<div v-for="message in chatMessages" :key="message.id" class="flex items-start min-w-64 w-fit max-w-[60%]" :class="{ 'ml-auto mr-0 flex-row-reverse': message.type === 'sent' }">
<div
class="flex items-center gap-2 sticky top-0 transition-all"
:class="{
'flex-row-reverse': message.type === 'sent'
}"
>
<Avatar
v-bind="message.image ? { image: message.image } : { label: message.capName }"
:class="{
'bg-blue-100 text-blue-950': !message.image
}"
class="w-10 h-10 text-sm font-medium"
shape="circle"
/>
<div>
<svg :class="message.type === 'received' ? 'fill-surface-100 dark:fill-surface-800' : 'fill-primary rotate-180'" class="" xmlns="http://www.w3.org/2000/svg" width="7" height="11" viewBox="0 0 7 11" fill="none">
<path d="M1.79256 7.09551C0.516424 6.31565 0.516426 4.46224 1.79256 3.68238L7 0.500055L7 10.2778L1.79256 7.09551Z" />
</svg>
</div>
</div>
<div :class="message.type === 'received' ? 'flex-1 bg-surface-100 dark:bg-surface-800 px-2 py-1 rounded-lg' : 'flex-1 bg-primary px-2 py-1 rounded-lg'">
<p :class="message.type === 'received' ? 'text-color leading-6 mb-0' : 'text-primary-contrast leading-6 mb-0'">
{{ message.message }}
</p>
<div v-if="message.attachment" :class="message.type === 'received' ? 'bg-surface-200 dark:bg-surface-700' : 'bg-primary-emphasis'" class="mt-2 w-full rounded-lg mb-0.5 hover:opacity-75 transition-all">
<img class="w-full h-auto block cursor-pointer" :src="message.attachment" alt="Message Image" />
</div>
</div>
</div>
</div>
<div class="p-4 border-t border-surface flex items-end justify-between gap-2">
<div class="flex items-end gap-1 flex-1">
<Button icon="pi pi-face-smile" text />
<Button icon="pi pi-paperclip" text />
<Textarea class="ml-1 flex-1 border-0 shadow-none max-h-32 min-h-9 bg-emphasis overflow-auto" autoResize rows="1" placeholder="Write your message..." />
</div>
<Button icon="pi pi-send" />
</div>
</div>
<div class="w-3/12 xl:block hidden min-w-40 py-6 px-3 overflow-auto">
<div class="flex flex-col items-center justify-center">
<Avatar image="https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar-primetek.png" class="w-32 h-32" size="xlarge" shape="circle" />
<div class="leading-6 font-medium text-color mt-4 w-full text-center">PrimeTek</div>
<div class="leading-5 text-sm text-muted-color mt-1 w-full text-center">@primetek</div>
<div class="flex items-center justify-center flex-wrap gap-1 mt-4">
<Button icon="pi pi-phone text-muted-color" severity="secondary" text />
<Button icon="pi pi-video text-muted-color" severity="secondary" text />
<Button icon="pi pi-sign-in text-muted-color" severity="secondary" text />
<Button icon="pi pi-info-circle text-muted-color" severity="secondary" text />
<Button type="button" icon="pi pi-ellipsis-v text-muted-color" severity="secondary" text @click="toggle" aria-haspopup="true" aria-controls="overlay_menu" />
<Menu ref="menu" id="overlay_menu" :model="menuItems" :popup="true" />
</div>
</div>
<div class="flex flex-col gap-4 mt-4">
<div class="flex items-center gap-2">
<i class="pi pi-bell text-color"></i>
<div class="leading-6 font-medium text-color flex-1">Notification</div>
<ToggleSwitch v-model="notification" />
</div>
<div class="flex items-center gap-2">
<i class="pi pi-volume-down text-color"></i>
<div class="leading-6 font-medium text-color flex-1">Sound</div>
<ToggleSwitch v-model="sound" />
</div>
<div class="flex items-center gap-2">
<i class="pi pi-download text-color"></i>
<div class="leading-6 font-medium text-color flex-1">Save to downloads</div>
<ToggleSwitch v-model="download" />
</div>
</div>
<div class="mt-6">
<div class="flex items-center gap-2">
<div class="flex-1 text-color leading-6 font-medium">Members</div>
<Button label="See All" class="text-sm py-0.5 px-2 text-muted-color" text />
</div>
<div class="mt-4 flex flex-col gap-4">
<div v-for="member in members" :key="member.name" class="flex items-center gap-2 cursor-pointer">
<Avatar
v-bind="member.image ? { image: member.image } : { label: member.capName }"
:class="{
'bg-orange-100 text-orange-950': !member.image
}"
class="font-medium text-xs"
shape="circle"
/>
<div class="text-sm text-color hover:text-muted-color-emphasis transition-colors font-medium leading-5 flex-1">
{{ member.name }}
</div>
<i class="pi pi-chevron-right text-xs text-muted-color"></i>
</div>
</div>
</div>
<div class="mt-5">
<SelectButton
v-model="media"
:options="mediaOptions"
:pt="{
root: {
class: 'w-full'
},
pcbutton: {
root: {
class: 'flex-1'
}
}
}"
/>
<div class="mt-3 mb-5 grid grid-cols-3 gap-2">
<div v-for="(media, index) in chatMedia" :key="index" class="bg-emphasis hover:opacity-70 transition-all flex-1 aspect-square rounded-lg border border-surface cursor-pointer">
<img class="w-full h-full object-cover block" :src="media" alt="Media Image" />
</div>
<div class="bg-emphasis hover:opacity-70 transition-all flex-1 aspect-square rounded-lg border border-surface cursor-pointer flex items-center justify-center">
<span class="text-muted-color font-medium">99+</span>
</div>
</div>
<Button
label="Show more"
icon="pi pi-arrow-right"
iconPos="right"
outlined
class="w-full text-left"
:pt="{
root: {
class: 'justify-between'
}
}"
/>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'Chat',
redrawListener: null,
data() {
return {
search: '',
download: false,
notification: true,
sound: false,
value: 'Chat',
value2: '',
options: ['Chat', 'Call'],
media: 'Media',
mediaOptions: ['Media', 'Link', 'Docs'],
activeChat: 'PrimeTek Team',
menuItems: [
{
label: 'Group Info',
icon: 'pi pi-info-circle'
},
{
label: 'Leave group',
icon: 'pi pi-sign-out'
}
],
chats: [
{
image: 'https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar11.jpg',
name: 'Cody Fisher',
capName: 'CF',
active: true,
unreadMessageCount: 8,
time: '12.30',
lastMessage: "Hey there! I've heard about PrimeVue. Any cool tips for getting started?"
},
{
image: 'https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar-primetek.png',
name: 'PrimeTek Team',
capName: 'PT',
active: undefined,
unreadMessageCount: 0,
time: '11.15',
lastMessage: "Let's implement PrimeVue. Elevating our UI game! 🚀"
},
{
image: 'https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar2.png',
name: 'Jerome Bell',
capName: 'JB',
active: true,
unreadMessageCount: 4,
time: '11.15',
lastMessage: "Absolutely! PrimeVue's documentation is gold—simplifies our UI work."
},
{
image: 'https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar12.jpg',
name: 'Robert Fox',
capName: 'RF',
active: false,
unreadMessageCount: 0,
time: '11.15',
lastMessage: "Interesting! PrimeVue sounds amazing. What's your favorite feature?"
},
{
image: 'https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar13.jpg',
name: 'Esther Howard',
capName: 'EH',
active: true,
unreadMessageCount: 9,
time: '11.15',
lastMessage: 'Quick one, team! Anyone using PrimeVue for mobile app development?'
},
{
image: 'https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar9.jpg',
name: 'Darlene Robertson',
capName: 'DR',
active: false,
unreadMessageCount: 0,
time: '11.15',
lastMessage: "Just explored PrimeVue's themes. Can we talk about those stunning designs? 😍"
},
{
image: 'https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar6.png',
name: 'Ralph Edwards',
capName: 'RE',
active: false,
unreadMessageCount: 0,
time: '11.15',
lastMessage: 'PrimeVue is a game-changer, right? What are your thoughts, folks?'
},
{ image: '', name: 'Ronald Richards', capName: 'RR', active: false, unreadMessageCount: 0, time: '11.15', lastMessage: "Jumping in! PrimeVue's community forum is buzzing. Any engaging discussions?" },
{ image: '', name: 'Kristin Watson', capName: 'KW', active: false, unreadMessageCount: 0, time: '11.15', lastMessage: 'Sharing a quick win-PrimeVue tutorials are leveling up my UI skills. 👩‍💻' },
{
image: 'https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar7.png',
name: 'Darrell Steward',
capName: 'DS',
active: false,
unreadMessageCount: 0,
time: '11.15',
lastMessage: "Reflecting on PrimeVue's impact on our workflow. What's your take?"
}
],
chatMessages: [
{ id: 1, attachment: '', name: '', image: '', capName: 'OS', type: 'received', message: "Awesome! What's the standout feature?" },
{ id: 2, attachment: '', name: '', image: 'https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar8.png', capName: 'A', type: 'received', message: 'PrimeVue rocks! Simplifies UI dev with versatile components.' },
{ id: 3, attachment: '', name: '', image: 'https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar11.jpg', capName: 'A', type: 'received', message: 'Intriguing! Tell us more about its impact.' },
{
id: 4,
attachment: 'https://www.primefaces.org/cdn/primevue/images/landing/apps/message-image.png',
name: '',
image: 'https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar2.png',
capName: 'A',
type: 'received',
message: "It's design-neutral and compatible with Tailwind. Features accessible, high-grade components!"
},
{ id: 5, attachment: '', name: '', image: 'https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar5.png', capName: 'A', type: 'sent', message: 'Customizable themes, responsive design UI excellence!' },
{ id: 6, attachment: '', name: '', image: 'https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar8.png', capName: 'A', type: 'received', message: 'Love it! Fast-tracking our development is key.' },
{ id: 7, attachment: '', name: '', image: 'https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar6.png', capName: 'A', type: 'received', message: 'Documentation rocks too smooth integration for all.' },
{
id: 8,
attachment: '',
name: '',
image: 'https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar5.png',
capName: 'B',
type: 'sent',
message: 'The flexibility and ease of use are truly impressive. Have you explored the new components?'
},
{
id: 9,
attachment: '',
name: '',
image: 'https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar12.jpg',
capName: 'C',
type: 'received',
message: 'Absolutely, the new calendar component has saved us a ton of development time!'
},
{
id: 10,
attachment: '',
name: '',
image: 'https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar13.jpg',
capName: 'D',
type: 'received',
message: "And the accessibility features are top-notch. It's great to see a library focusing on inclusivity."
},
{
id: 11,
attachment: 'https://www.primefaces.org/cdn/primevue/images/landing/apps/message-image.png',
name: '',
image: 'https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar5.png',
capName: 'E',
type: 'sent',
message: "I couldn't agree more. Plus, the documentation is incredibly thorough, which makes onboarding new team members a breeze."
},
{
id: 12,
attachment: '',
name: '',
image: 'https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar6.png',
capName: 'F',
type: 'received',
message: 'Do you have any tips for optimizing performance when using multiple complex components?'
},
{
id: 13,
attachment: '',
name: '',
image: 'https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar11.jpg',
capName: 'G',
type: 'received',
message: 'Yes! Lazy loading and code splitting can make a huge difference, especially in larger applications.'
},
{
id: 14,
attachment: '',
name: '',
image: '',
capName: 'HS',
type: 'received',
message: "I've also found that leveraging the component's internal state management capabilities can help streamline data flow and improve performance."
},
{
id: 15,
attachment: '',
name: '',
image: 'https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar5.png',
capName: 'H',
type: 'sent',
message: "That's great advice. It's amazing how much detail and thought has gone into making PrimeVue such a powerful tool for developers."
}
],
chatMedia: [
'https://www.primefaces.org/cdn/primevue/images/landing/apps/chat-image1.png',
'https://www.primefaces.org/cdn/primevue/images/landing/apps/chat-image2.png',
'https://www.primefaces.org/cdn/primevue/images/landing/apps/chat-image3.png',
'https://www.primefaces.org/cdn/primevue/images/landing/apps/chat-image4.png',
'https://www.primefaces.org/cdn/primevue/images/landing/apps/chat-image5.png'
],
members: [
{ name: 'Robin Jonas', capName: 'RJ', image: 'https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar2.png' },
{ name: 'Cameron Williamson', capName: 'CW', image: 'https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar11.jpg' },
{ name: 'Eleanor Pena', capName: 'EP', image: 'https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar5.png' },
{ name: 'Arlene McCoy', capName: 'AM', image: 'https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar8.png' },
{ name: 'Dianne Russell', capName: 'DR', image: '' }
]
};
},
methods: {
toggle(event) {
this.$refs.menu.toggle(event);
}
},
components: {}
};
</script>