Change PrimeVue ChatApp ShowCase from Options API to Composition API.
Organized into three panels.
Change PrimeVue ChatApp ShowCase from Options API to Composition API.
Organized into three panels.
<template> | |
<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-primary-100 text-primary-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> | |
</template> | |
<script setup lang="ts"> | |
const menuItems = ref([ | |
{ | |
label: "Group Info", | |
icon: "pi pi-info-circle", | |
}, | |
{ | |
label: "Leave group", | |
icon: "pi pi-sign-out", | |
}, | |
]); | |
const chatMessages = ref([ | |
{ | |
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.", | |
}, | |
]); | |
const menu = ref(); | |
function toggle(event: any) { | |
menu.value.toggle(event); | |
} | |
</script> |
<template> | |
<div | |
class="flex-1 h-full overflow-y-auto overflow-x-clip overflow-hidden flex border border-surface rounded-2xl" | |
> | |
<LeftPanel /> | |
<CenterPanel /> | |
<RightPanel /> | |
</div> | |
</template> | |
<script setup lang="ts"></script> |
<template> | |
<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-primary-100 !text-primary-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> | |
</template> | |
<script setup lang="ts"> | |
const search = ref(""); | |
const value = ref("Chat"); | |
const options = ref(["Chat", "Call"]); | |
const activeChat = ref("PrimeTek Team"); | |
const chats = ref([ | |
{ | |
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?", | |
}, | |
]); | |
</script> |
<template> | |
<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> | |
</template> | |
<script setup lang="ts"> | |
const download = ref(false); | |
const notification = ref(true); | |
const sound = ref(false); | |
const media = ref("Media"); | |
const mediaOptions = ref(["Media", "Link", "Docs"]); | |
const menuItems = ref([ | |
{ | |
label: "Group Info", | |
icon: "pi pi-info-circle", | |
}, | |
{ | |
label: "Leave group", | |
icon: "pi pi-sign-out", | |
}, | |
]); | |
const chatMedia = ref([ | |
"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", | |
]); | |
const members = ref([ | |
{ | |
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: "" }, | |
]); | |
const menu = ref(); | |
function toggle(event: any) { | |
menu.value.toggle(event); | |
} | |
</script> |